1.1 Java 内存模型
1.2.1 JMM 核心原则
1.4 JMM 影响范围
2.1 数据依赖性
2.1.1 串行语义
2.2 重排序
2.3 Happends-Before 规则
■ volatile
3.1 volatile 工作原理
- int a = 0;
- volatile boolean flag = false;
- public void write() {
- a = 1;
- flag = true;
- }
- public void read() {
- if (flag) {
- int i = a;
- }
- }
写内存语义: 当写一个 volatile 变量时,JMM 会把线程对应的本地内存中的共享变量,到主内存
读内存语义:
3.2 volatile 可见性原理
- public class VolatileDemo {
- public volatile int count = 0;
- public void addCount() {
- count++;
- //需要注意的是 count++换成 count += 1 效果也是一样,因为都是复合操作,不单单只是的++这种操作
- }
- public static void main(String[] args) {
- VolatileDemo volatileDemo = new VolatileDemo();
- Thread[] threads = new Thread[10];
- for (int i = 0; i < threads.length; i++) {
- threads[i] = new Thread(new Runnable() {@Override public void run() {
- for (int j = 0; j < 1000; j++) {
- volatileDemo.addCount();
- }
- }
- });
- }
- //我们减少new的开销,让结果更准确一些
- for (int i = 0; i < threads.length; i++) {
- threads[i].start();
- }
- //线程需要都执行完毕
- while (Thread.activeCount() > 1) {
- //让主线程主动释放资源,也就是等会在干活
- //用Thread.sleep(long)效果一样,但时间不好控制
- Thread.yield();
- }
- System.out.println("结果是:" + volatileDemo.count);
- }
- }
- //结果是:9936
- //于我们的预期结果10000完全不相符,说明volatile根本就不能保证原子性
3.4 volatile 应用场景
正确使用 volatile 的条件:
volatile 使用场景:
正确使用 volatile:
- ============= 状态标识 ===========================================
- //使用:作为一个布尔状态标志,用于指示发生了一个重要的一次性事件,例如完成初始化或任务结束
- //使用理由:状态标志并不依赖于程序内任何其他状态,且通常只有一种状态转换
- //例子:判断业务是否结束
- volatile boolean isOk = false;
- public void isOk() { isOk = true; }
- public void doWork() {
- //循环监听状态位变化
- while (!isOk) {
- // do work
- }
- }
- === ==========独立观察 === ========================================
PS: JMM 和 volatile 博文暂时到此,有很多原理和高级主题后续会陆续迭代研究,请各位观众多多评语、鼓励,谢谢!
- //使用:将 volatile变量用于多个独立观察结果的发布 //特点:是"状态标志"的拓展,该值随时会发生变化,同时会被反复使用,前者一般就是用一次 //使用理由:只是简单的赋值操作,不会做复合操作 //例子:将新节点作为最后一个节点
- class CustomLinkedList{
- public volatile Node lastNode;
- ......
- public void add() { Node node = new Node(); .....
- lastNode = node; //将新节点作为最后一个节点 } }
来源: https://www.cnblogs.com/romanjoy/p/8125703.html