线程安全之可见性(二)
一:不可见的原因
上一部分,根据代码可以知道,产生不可见的原因有两点:
1:CPU高速缓存会造成极短时间内数据的不可见
2:指令重排是导致不可见的主要原因
二:Java内存模型(JMM)
java内存模型主要是描述多线程程序的语义,多个线程对数据进行了修改,该读取哪个的问题;Java内存模型并没有规定如何去实现多线程程序,只是制定了一些合法行为,即规则;Java内存模型对内存分为工作内存和主内存,也就是栈内存和堆内存。
三:线程间的操作
java内存模型只规定线程间的操作,有以下几种:read,write,volidate read,volidate write,线程start和start的线程的第一步操作,线程结束。
冲突和数据竞争:冲突就是线程间,有一个读操作和一个写操作,造成了冲突
四:JMM规则
1:同步规则
1.1 volidate的写操作,对后续volidate的读操作同步。
也就是说用volidate修饰的变量,写入后,对其他线程是可见的。
1.2 unlock之后的操作,对后续的lock同步。
加锁和解锁不能重排序,也不能缓存,和volidate一样,t1线程释放锁之后,对后续的加锁是可见的。
1.3 t1线程的start操作,对t1的第一步操作同步。
也就是说,再主线程内启动t1,对t1线程内部的操作是可见的。其实就是t1线程再启动之前是NEW状态,主线程把t1线程实例化后,主内存中保存了t1的状态信息,start之后,t1线程的状态变为RUNNABLE,这个状态对t1是可见的,不能够缓存。
1.4 t1线程最后一步的操作,对后续的线程是可见的。
和1.3一样,也是在主内存中的状态信息是可见的,不能被缓存。
1.5 t1线程的interrupt操作,对其他线程是同步的。
interrupt操作后,对其他线程是可见的。
2:happens-before(先行发生原则)
2.1 volidate的写操作,happens-before其他线程的读操作,即写操作发生在读操作之前。
2.2 线程的unlock操作,happens-before其他线程的lock操作。
2.3 线程的start操作,happens-before此线程的所有操作。
2.4 若在t1线程中使用了t2.join,那么t2的操作对t1是可见的。
2.5 若A happens-before B,B happens-before C,那么A happens-before C。