volatile变量的写-读可以实现线程之间的通信。
从内存定义的角度来说,volatile的写-读与锁的释放-获取有相同的内存效果。
happens-before介绍(都是针对成员变量和静态成员变量)
如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。这里提到的两个操作可以是一个线程之内(一个线程可以有多个操作),也可以是不同线程之间。
happens- before规则
1 程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。
2 监视器锁规则:对于一个锁的解锁,happens-before之后是对这个锁的加锁。
3 volatile变量规则:对一个volatile域的写,happens-before之后是对volatile域的读。
4 传递性: 如果A happens-before B,B happens-before C,那么A happens-before C。
注意⚠️
两个操作之间有happens-before的关系,不一定是A操作在B操作之前执行。如果重排序之后执行的结果,与按照happens-before关系来执行的结果一致,那么这种重排序并不非法。
简单来说如果前一个操作happens-before后一个操作,只需要前一个操作执行的结果对后一个操作可见,而且前一个操作的顺序在第二个操作之前。这是JMM对程序员做出的保证。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
重程序员的角度来说,如果A happens-before B,那么只需要A执行的操作结果对B可见,并且A的执行顺序在B前面。(⚠️这只是Java内存模型向程序员做出的保证)。
5 start()规则:如果线程A执行操作ThreadB•start(),那么线程A的ThreadB.start()happens-before线程B中的任意操作。
换句话说就是A执行的ThreadB.start()(包括线程A的操作在ThreadB.start()之前的操作)对于B线程的所有操作来说都是可见的,并且操作顺序在B线程的所有操作之前。
6 join()规则,如果线程A执行操作ThreadB.join()并且成功返回,那么线程B中的任意操作于happens-before线程A从ThreadB.join()操作成功返回。
也就是说线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作对A线程可见,并且B线程的所有操作在A线程执行ThreadB.join()之前。
……参考资料《java并发编程的艺术》