• volatile


    一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

    内存可见性:即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的

    内存屏障(memory barrier):如果你的字段是volatile,Java内存模型将在写操作后插入一个写屏障指令,在读操作前插入一个读屏障指令。这意味着如果你对一个volatile字段进行写操作,你必须知道:1、一旦你完成写入,任何访问这个字段的线程将会得到最新的值。2、在你写入前,会保证所有之前发生的事已经发生,并且任何更新过的数据值也是可见的,因为内存屏障会把之前的写入值都刷新到缓存

     例如你让一个volatile的integer自增(i++),其实要分成3步:1)读取volatile变量值到local; 2)增加变量的值;3)把local的值写回,让其它的线程可见。这3步的jvm指令为

    mov    0xc(%r10),%r8d ; Load
    inc    %r8d           ; Increment
    mov    %r8d,0xc(%r10) ; Store
    lock addl $0x0,(%rsp) ; StoreLoad Barrier

       注意最后一步是内存屏障,写屏障指令

    内存可见性

    /**
     * volatile可以保证属性的可见性,一个线程修改了,另一个线程可以立刻知道该线程被修改了
     *
     */
    public class VolatileTest {
    
        private static volatile  int INIT_VALUE = 0;
    
        private final static int MAX_LIMIT = 5;
    
        public static void main(String[] args) {
            new Thread(() -> {
                int localValue = INIT_VALUE;
                while (INIT_VALUE < MAX_LIMIT) {
                    System.out.printf("Update the value to [%d]
    ", ++localValue);
                    INIT_VALUE = localValue;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "UPDATER").start();
            
            new Thread(() -> {
                while (INIT_VALUE <  3) {
                    
                }
                System.out.println("结束循环了");
            }, "READER").start();
    
        }
    }

    内存屏障,防止重排序

    class Singleton {
        private volatile static Singleton instance = null;
         
        private Singleton() {
             
        }
         
        public static Singleton getInstance() {
            if(instance==null) {
                synchronized (Singleton.class) {
                    if(instance==null)
                        instance = new Singleton();
                }
            }
            return instance;
        }
    }

    volatile不具备原子性

    public class VolatileTest {
        
        private static volatile long value = 0;
    
        public static void main(String[] args) throws InterruptedException {
    
            Thread t1 = new Thread(new LoopVolatile());
            t1.start();
    
            Thread t2 = new Thread(new LoopVolatile2());
            t2.start();
    
            t1.join();
            t2.join();
            System.out.println("final val is: " + value);  // final val is: 18585
        }
    
        private static class LoopVolatile implements Runnable {
            public void run() {
                long val = 0;
                while (val < 10000L) {
                    value++;
                    val++;
                }
            }
        }
    
        private static class LoopVolatile2 implements Runnable {
            public void run() {
                long val = 0;
                while (val < 10000L) {
                    value++;
                    val++;
                }
            }
        }
    }

    CPU高速缓存

    JMM  java内存模型

  • 相关阅读:
    统一前后台数据交互格式
    volatile关键字 学习记录2
    利用AOP与ToStringBuilder简化日志记录
    JAVA的那些数据结构实现总结,实现,扩容说明
    JAVA中的数据结构
    对把JDK源码的一些注解,笔记
    分析下为什么spring 整合mybatis后为啥用不上session缓存
    JAVA内存关注总结,作为个程序员需要对自己系统的每块内存做到了如指掌
    写颗搜索二叉树动动脑,开启今年的旅程,新年快乐
    内存快照排查OOM,加密时错误方法指定provider方式错误引起的OOM
  • 原文地址:https://www.cnblogs.com/moris5013/p/10706547.html
Copyright © 2020-2023  润新知