【Java多线程】volatile原理&happens-before规则
1.Java 内存模型中的可见性、原子性和有序性1.1 可见性可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。1.2 原子性原子是世界上的最小单位,具有不可分割性。1.3 有序性Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“
1.Java 内存模型中的可见性、原子性和有序性
1.1 可见性
可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。
可见性问题由JVM缓存优化引起。
1.2 原子性
原子是世界上的最小单位,具有不可分割性。
1.3 有序性
Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。
有序性问题由JVM指令重排序优化引起。
2.保证可见性
写屏障:写屏障保证在该屏障之前的,所有共享变量的修改都同步到主存中。
读屏障:保证在该屏障之后,对共享变量的读取,取的是主存中的最新数据。
3.保证有序性
写屏障:防止指令重排,防止写屏障之前的代码出现在写屏障后面
读屏障:保证在读屏障之后的代码不会排在读屏障前面。
有序性的保证也只是保证了本线程内相关代码不被重排序。
4.volatile不能保证原子性
5.double-checked locking
5.1 举例
5.1.1 问题
5.1.2 纠正
如果把共享变量INSTANCE完全放在synchronized所保护的代码块之内,就能防止指令重排。
5.1.3 解决
在共享变量INSTANCE上加volatile,解决指令重排序。
6.happens-before规则
happens-before规定了对共享变量的写操作对其他线程的读操作可见,它是可见性与有序性的一套规则总结,抛开以下happens-before规则,JMM并不能保证一个线程对共享变量的写,对于其他线程对该共享变量的读可见
6.0 更新博文中的happends-before
6.1及以后不必看了
感觉下面的不好,所以重新写了
参考:https://www.jianshu.com/p/9464bf340234
1.程序的顺序性规则
在一个线程内一段代码的执行结果是有序的。就是还会指令重排,但是随便它怎么排,结果是按照我们代码的顺序生成的不会变。
2.volatile规则
如果一个线程先去写一个volatile变量,然后一个线程去读这个变量,那么这个写操作的结果一定对读的这个线程可见。
3.传递性规则
即hb(A, B) , hb(B, C),那么hb(A, C)。
4.管程中的锁规则
一个线程对这个锁解锁之后,另一个线程获取了这个锁都能看到前一个线程的操作结果。
(管程是一种通用的同步原语,synchronized就是管程的实现)
5.线程start()规则
主线程A启动线程B,线程B中可以看到主线程启动B之前的操作。
6.线程join()规则
主线程A等待子线程B完成,当子线程B执行完毕后,主线程A可以看到线程B的所有操作。
6.1 线程解锁m之前对变量的写,对于接下来对m加锁的其他线程对该变量的读可见
6.2 线程对volatile变量的写,对接下来其他线程对该变量的读可见
6.3 线程start前对变量的写,对该线程开始后对该变量的读可见
6.4 线程结束前对变量的写,对其他线程得知它结束后的读可见
6.5 线程t1打断(interrupt)t2前对变量的写,对于其他线程得知t2被打断后对该变量的读可见(通过t2.interrupted或t2.isInterruped)
6.6 对变量默认值(0,false,null)的写,对其他线程对该变量的读可见
6.7 具有传递性,如果A happens-before B,且B happens-before C,那么 A happens-before C
/
/-------------------------------------------------------我是一条没有感情的分割线--------------------------------------/
更多推荐
所有评论(0)