多线程-JMM从底层解决线程安全

一:什么是JMM

  从字面上理解JMM(Java Memory model)就是java定义了一个底层内存操作的一个抽象。

  当多线程同时对共享变量进行操作时,会存在原子性,可见性,有序性问题。JMM抽象定义了每个线程有自己的本地内存,共享变量存在主内存中,JMM通过控制主内存与线程的本地内存的交互来保证线程之间的可见性。

  通过抽象JMM可以让程序员使用JMM定义的规则合理的按需禁用缓存、编译器优化,从源头上解决可见性、重排序问题

 

二:如何理解JMM

  JMM可以从源头上解决可见性、重排序问题,而它的核心部分就是happens-before与as-if-serial规则,只要充分理解happens-before,程序员就能理解透并发编程中的可见性问题,只要充分理解as-if-serial,程序员就能理解透并发编程中的重排序问题。

 

2.1:happens-before吃透可见性问题

 happens-before规则是用来描述操作之间的内存可见性问题,在JMM里,如果一个操作对另外一个操作可见,两个操作之间就必须要保证happens-before关系,这里提到的两个操作可以是在一个线程内,也可以是不同线程中。

 做了这么多铺垫,我们来看看happens-before规则到底是什么,其实很简单,总共只有7条规则,和一个特性。(再强调一次:两个操作具有happens-before规则不意味前一个操作再另一个操作之前执行,而是前一操作对另一操作可见,且前一操作顺序排在第二个操作之前)

 

2.1.1:七个规则

   1、程序顺序规则:一个线程中的每个操作,happens-before该线程中的任意后续操作。

   2、监视器锁规则(涉及Java中的关键字其实就是synchronized):对一个锁的解锁,happens-before随后对这个锁的加锁。

   3、volatile规则:对一个volatile变量的写,happens-before于任意后续对这个volatile变量的读。

   4、线程启动规则:Thread对象的start()方法happens-before于此线程的每一个动作。

   5、线程终止规则:线程中所有操作都happens-before对此线程的终止操作。

   6、线程中断规则:对线程interrupt()方法的调用happens-before于被中断线程的代码检测到中断事件的发生。

   7、对象终结规则:一个对象的初始化happens-before它的finalize()方法的开始。

2.1.2:一个特性

   这条规则是指如果 A happens-before B,且 B happens-before C,那么 A happens-before C。

 

2.2:as-if-serial吃透重排序问题

   as-if-serial语义规定在单线程中无论怎么重排序,程序的执行结果不能被改变。因为两个操作存在数据依赖as-if-serial会禁止重排序。

多线程-JMM从底层解决线程安全_第1张图片

如果上表这三种情况出现重排序时,会改变执行结果。

2.3:上代码实践

int a=0;
boolean flag=false;

public void write(){
//1 a=2;
//2 flag=true;
}

public void read(){
//3 if(flag){
//4 System.out.println(a);
}
}

 启动线程a和线程b,线程a执行write,然后线程b执行read(),由于操作1,2没有依赖性,当1,2进行重排序,此时线程b看不到a的改变。

int a=0;
volatile boolean flag=false;

public void write(){
//1 a=2;
//2 flag=true;
}

public void read(){
//3 if(flag){
//4 System.out.println(a);
}

根据happens-before 程序次序规则,1 happens-before 2;3 happens-before 4。

根据happens-before volatile规则 ,2 happens-before 3

根据happens-before 传递下特性 ,此时可以推断出 1 happens-before 4

当使用volatile关键字,此时happens-before规则向程序员保证 b一定可以看到a线程写数据的操作,在使用多线程时就不会留下安全隐患。

:总结

   通过以上案例,可以发现我们只要理解透JMM,对以后并发编程出现的问题就可以通过推导判断。而JMM底层实现,是通过内存屏障(memory barrier)禁止重排序实现的,如果对这块感兴趣后面文章会讲解。

你可能感兴趣的:(Java,并发,Java并发编程笔记)