天天看点

多线程特性(原子性、可见性、有序性)多线程特性

多线程特性

原子性

​ 所谓原子性即:一个或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

​ 在原子操作中,本质上拒绝多线程操作的,不论是单核或多核服务器,当要对某一个数据进行原子操作时,同一时刻只有有一个线程能够对其进行操作,简单来说,在整个操作过程中不会被线程调度器打断,如a=1就是一个原子操作,但a++则不是一个原子操作,因为其内部会额外产生一个新的Integer对象。

​ 举个例子,假设对一个32位的变量赋值,操作分为两步:低16位赋值、高16位赋值。当线程A对低16位数据写入成功后,线程A被中断。而此时另外的线程B去读取a的值,那么读取到的就是错误的数据。

​ 在Java中的原子性操作包括:

基本类型的读取和赋值操作,且赋值必须是数字赋值给变量,变量之间的相互赋值不是原子性操作。

所有引用的赋值操作。

java.concurrent.Atomic.* 包中所有原子操作类的一切操作。

测试

public class test {
    public static void main(String[] args) throws InterruptedException {
        MyInt myInt = new MyInt();
        for(int i=0;i<2;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true){
                        System.out.println(Thread.currentThread().getName()+"----->"+myInt.getNum());
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                }
            }).start();
        }
    }
    static  class MyInt{
        int num;
        public int getNum(){
          return   num++;
        }
    }
}
           
多线程特性(原子性、可见性、有序性)多线程特性

可见性

所谓可见性:即当多个线程访问同一个共享变量时,一个线程修改了该共享变量的值后,其他线程能够立即查看到修改后的值。

​ 在多线程环境下,一个线程对共享变量的操作对其他线程是默认是不可见的,也就是说一个线程对某一共享的修改,默认其他线程是无法进行查看的。而如果要做到可见,Java中的volatile、synchronized、Lock都能保证可见性。如一个变量被volatile修饰后,表示当一个线程修改共享变量后,其会立即被更新到主内存中,其他线程读取共享变量时,会直接从主内存中读取。而synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。

有序性

所谓有序性:即程序执行的顺序会按照代码的先后顺序执行。

​ 其可以理解为在本线程内,所有的操作都是有序的。而如果在A线程中观察B线程,所有的操作都是无序的。在JMM中为了提升程序的执行效率,允许编译器和处理器对指令重排序。对于单线程来说,指令重排并不会产生问题,而在多线程下则不可以。

​ 在Java中可以通过synchronized和Lock来保证有序性,synchronized和Lock保证每个时刻是有一个线程执行同步代码,相当于是让线程顺序执行同步代码,自然就保证了有序性。

继续阅读