⑤. JVMM规范下,多线程先行发生原则之happens-before
①. 先行发生原则说明
①. 如果Java内存模型中有序性仅靠volatile和synchronized来完成,那么有很多操作都将会变得非常啰嗦,但是我们在编写Java并发代码的时候并没有察觉到这一点
②. 我们没有时时、处处、次次,添加volatile和synchronized来完成程序,这是因为Java语言中JMM原则下,有一个"先行发生"(Happens-Before)的原则限制和规则
③. 在JMM中,如果一个操作执行的结果需要对另一个操作可见性或者代码重排序,那么这两个操作之间必须存在happens-before关系
④. x、y案例说明
②. happens-before总原则
①. 如果一个操作happens-before另一个操作,那么第一个操作的执行结果对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前(可见性,有序性)
②. 两个操作之间存在happens-before关系,并不意外着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序并不非法(可以指令重排)
(值日:周一张三周二李四,假如有事情调换班可以的1+2+3=3+2+1)
③. happens-before之8条
①. 次序规则
一个线程内,按照代码顺序,写在前面的操作先行发生于写在后面的操作(强调的是一个线程)
前一个操作的结果可以被后续的操作获取。将白点就是前面一个操作把变量X赋值为1,那后面一个操作肯定能知道X已经变成了1
②. 锁定规则
(一个unlock操作先行发生于后面((这里的"后面"是指时间上的先后))对同一个锁的lock操作(上一个线程unlock了,下一个线程才能获取到锁,进行lock))
③. volatile变量规则
(对一个volatile变量的写操作先行发生于后面对这个变量的读操作,前面的写对后面的读是可见的,这里的"后面"同样是指时间是的先后)
④. 传递规则
(如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出A先行发生于操作C)
⑤. 线程启动规则(Thread Start Rule)
(Thread对象的start( )方法先行发生于线程的每一个动作)
⑥. 线程中断规则(Thread Interruption Rule)
对线程interrupt( )方法的调用先发生于被中断线程的代码检测到中断事件的发生
可以通过Thread.interrupted( )检测到是否发生中断
⑦. 线程终止规则(Thread Termination Rule)
(线程中的所有操作都先行发生于对此线程的终止检测)
⑧. 对象终结规则(Finalizer Rule)
(对象没有完成初始化之前,是不能调用finalized( )方法的 )
④. 案例说明
①. 代码展示、问题暴露、解决方案
private int value=0; public void setValue(){ this.value=value; } public int getValue(){ return value; }
②. 解决方案
把getter/setter方法都定义synchronized方法(某一时刻只能有一个线程进入)
把value定义为volatile变量,由于setter方法对value的修改不依赖value的原值,满足volatile关键字的使用
(对一个volatile变量的写操作先行发生于后面对这个变量的读操作,前面的写对后面的读是可见的,这里的"后面"同样是指时间是的先后)