并发编程(四)volatile关键字

简介: 并发编程(四)volatile关键字

volatile原理与内存语义

volatileJVM提供的轻量级的同步机制

  1. volatile语义有以下两个作用:
  • 可见性:保证被volatile修饰的共享变量对所有线程总是可见的,也就是当一个线程修改了一个被volatile修饰共享变量的值,新值总是可以被其他线程立即得知。
  • 有序性:禁止指令重排。
  1. volatile缓存可见性实现原理:
  • JVM交互层面,在操作对被volatile修饰的共享变量时,read,load,useassign,store,write必须是连续的,即修改后必须立即同步会主内存,使用时必须从主内存刷新,由此保证volatile变量的可见性。(但useassign不是连续执行,由此可见volatile并不保证原子性)
  • 底层实现:通过汇编lock前缀指令,它会锁定变量缓存行区域并写回主内存,这个操作称为“缓存锁定”,缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域数据。一个处理器的缓存回写到主内存会导致其他处理器的缓存无效

查看汇编指令:-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -Xcomp

public class DecompilationTest {
    public static volatile int age = 18;
    public static void main(String[] args) {
    }
}

properties

  0x00000000030b205b: nopl   0x0(%rax,%rax,1)
  0x00000000030b2060: jmpq   0x00000000030b20f4  ;   {no_reloc}
  0x00000000030b2065: add    %al,(%rax)
  0x00000000030b2067: add    %al,(%rax)
  0x00000000030b2069: add    %bh,0x12(%rdi)
  0x00000000030b206f: mov    %edi,0x68(%rsi)
  0x00000000030b2072: lock addl $0x0,(%rsp)     ;*putstatic age
                                                ; - com.my.juc.test.volatiletest.DecompilationTest::<clinit>@2 (line 10)

从以上截取的部分汇编指令中我们可以看到age变量确实加了lock前缀

volatile 保证可见性

public class VisualizationTest {
    public static
    volatile //若不加volatile修饰,则线程1一直运行
    boolean flag = true;
    static Lock lock = new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {
        String name = "Thread-1";
        new Thread(()->{
            System.out.println(name + " 启动中......");
            while (flag){
                /*lock.lock(); //加锁,使得发生上下文切换,将变量重新从主内存读取
                lock.unlock();*/
//                synchronized (VisualizationTest.class){}
            }
            System.out.println(name + " 执行完毕......");
        },name).start();
        TimeUnit.SECONDS.sleep(1);
        String name2 = "Thread-2";
        new Thread(()->{
            flag = false;
            System.out.println(name2 + " 修改静态变量flag:"+flag);
        }, name2).start();
    }
}

volatile 禁止指令重排

public class ReOrderTest {
    public 
    volatile //不加volatile则将出现x=0,y=0的情况 
    static int a = 0, b = 0;
    public static int x = 0, y = 0;
    public static void main(String[] args) throws InterruptedException {
        long count = 0;
        for (; ; ) {
            count++;
            a = b = x = y = 0;
            Thread t1 = new Thread(() -> {
                //由于线程1先执行,等一会线程2
                nanosWait(50000);
                a = 1;
                x = b;
            });
            Thread t2 = new Thread(() -> {
                b = 1;
                y = a;
            });
            //x = 0, y = 1
            //x = 1, y = 0
            //x = 1, y = 1
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            if (x == 0 && y == 0) {
                System.err.println("第" + count + "次循环,x=" + x + ",y=" + y);
                return;
            } else
                System.out.println("第" + count + "次循环,x=" + x + ",y=" + y);
        }
    }
    public static void nanosWait(long time) {
        long start = System.nanoTime();
        while (System.nanoTime() - start < time){}
    }
}
目录
相关文章
|
7月前
|
安全 算法 Java
多线程(初阶四:synchronized关键字)
多线程(初阶四:synchronized关键字)
55 0
|
2月前
|
缓存 Java 编译器
【多线程-从零开始-伍】volatile关键字和内存可见性问题
【多线程-从零开始-伍】volatile关键字和内存可见性问题
44 0
|
7月前
|
安全 Java 编译器
Java多线程基础-6:线程安全问题及解决措施,synchronized关键字与volatile关键字(一)
线程安全问题是多线程编程中最典型的一类问题之一。如果多线程环境下代码运行的结果是符合我们预期的,即该结果正是在单线程环境中应该出现的结果,则说这个程序是线程安全的。 通俗来说,线程不安全指的就是某一代码在多线程环境下执行会出现bug,而在单线程环境下执行就不会。线程安全问题本质上是由于线程之间的调度顺序的不确定性,正是这样的不确定性,给我们的代码带来了很多“变数”。 本文将对Java多线程编程中,线程安全问题展开详细的讲解。
107 0
|
7月前
|
Java 编译器
Java多线程:什么是volatile关键字?
Java多线程:什么是volatile关键字?
63 0
|
算法 安全 Java
多线程之volatile关键字
多线程之volatile关键字
|
SQL 缓存 安全
Java并发编程学习系列七:深入了解volatile关键字
Java并发编程学习系列七:深入了解volatile关键字
118 0
Java并发编程学习系列七:深入了解volatile关键字
|
存储 缓存 Java
JUC并发编程——深入了解volatile关键字
JUC并发编程——深入了解volatile关键字
155 0
JUC并发编程——深入了解volatile关键字
|
存储 缓存 安全
Java并发:volatile关键字详解
volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制,但是它并不容易完全被正确、完整地理解,以至于许多程序员都习惯不去使用它,遇到需要处理多线程数据竞争问题的时候一律使用synchronized来进行同步。了解volatile变量的语义对了解多线程操作的其他特性很有意义,在本文中我们将介绍volatile的语义到底是什么。由于volatile关键字与Java内存模型(Java Memory Model,JMM)有较多的关联,因此在介绍volatile关键字前我们会先介绍下Java内存模型。
168 0
Java并发:volatile关键字详解
|
存储 缓存 Java
Java并发编程之Volatile关键字解析
在java的并发编程中我们经常会使用到Volatile关键字。而关于Volatile关键字的使用以及Volatile关键字的特性和实现原理也是在笔面试中经常会遇到的问题了。
114 0
Java并发编程之Volatile关键字解析
|
缓存 Java 编译器
Java并发编程学习笔记:volatile关键字解析
Java并发编程学习笔记:volatile关键字解析