JAVA并发编程:三大特性-可见性、有序性

生活

生活就是生下来,活下去。

————

在JAVA并发编程,如果要保证程序的线程安全,就要保证代码的原子性、可见性、有序性。
昨天聊了原子性。今天来看下可见性、有序性。


什么是可见性?

当多个线程访问同一个变量时,一个线程修改了一个变量的值,其他线程可以马上读取到修改后的值。

可见性问题

场景说明:
两个线程共享一个变量stop.
A线程,当stop为false,则一直运行;为true则停止。
B线程,设置stop为true

public class Test {
    static  boolean stop;

    public static void main(String[] args) throws InterruptedException {

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程A运行中");
                while (!stop);
                System.out.println("线程A已停止");
            }
        }).start();

        Thread.sleep(10);


        new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("线程B运行中");
               stop = true;
               System.out.println("stop设置为true,线程B已停止");
           }
       }).start();
    }
}

其中一次运行结果:
线程A运行中
线程B运行中
stop设置为true,线程B已停止

由此见得,一个普通的变量在多线程环境下不具有可见性。

可见性的技术保障

1、Lock
2、synchronized
3、原子类
4、volatile

Lock和synchronized不用说,都是互斥锁,保障了共享资源在同一时刻只有一个线程可以访问,就不会出现可见性的问题。
volatile保障了一个变量修改以后马上写回主内存让其他线程可以看到,具体的分析后面再说。
至于原子类为什么也有可见性,因为他里面的value本身也是volatile修饰的。

关于volatile的详细解析,后面开一篇细聊。


什么是有序性?

即程序执行的顺序按照代码的先后顺序执行。
编译器和处理器为了提高执行的效率性能,会对执行进行重排序,指令重排序对单线程应用没有影响,但是在多线程环境下可能会出现问题。

有序性问题

线程A

扫描二维码关注公众号,回复: 4267334 查看本文章
context = loadContext();  
inited = true; 

线程B


while(!inited ){  
 sleep  
}  
doSomethingwithconfig(context); 

假设线程A发生重排序:

inited = true; 
context = loadContext();  

在这种情况下,B线程可能会拿到没有初始化的变量context。

有序性的技术保障

1、synchronized
2、lock
3、volatile(一定程度的有序性)
synchronized和lock在同一时刻只能让一个线程执行同步方法,当然就是有序的了。
volatile的有序性是指写入修改后的volatile变量这个操作必定优先于 读取这个变量。

猜你喜欢

转载自blog.csdn.net/qq_28605513/article/details/84558931