A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 专注的一批 中级黑马   /  2020-8-7 11:43  /  1645 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

一、特点

保证可见性:如果变量被 volatile 修饰,那么每次修改之后,接下来在读取这个变量的时候一定能读取到该变量最新的值。

不保证原子性

禁止指令重排

二、代码

1.验证volatile的可见性

import java.util.concurrent.TimeUnit;

class Share {

public volatile int num1 = 0;

public int num2 = 0;

public void method1() {

try {

TimeUnit.SECONDS.sleep(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

this.num1 = 1;

}

public void method2() {

try {

TimeUnit.SECONDS.sleep(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

this.num2 = 1;

}

}

public class Solution {

public static void main(String[] args) {

Share share = new Share();

//验证volatile的可见性

new Thread(() -> {

share.method1();

}).start();

while (share.num1 == 0) {

}

System.out.println("num1 break loop, num1 = " + share.num1);

//验证非volatile的不可见性

new Thread(() -> {

share.method2();

}).start();

while (share.num2 == 0) {

}

System.out.println("num2 break loop, num2 = " + share.num2);

}

}

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748

num1用volatile修饰,拥有可见性,而num2不拥有可见性。证明了volatile可以保证变量的可见性
外汇经纪商买卖价https://www.fx61.com/quotesbuy.html

2.双重检验锁机制的单例模式

class Singleton {

private static volatile Singleton instance = null;

private Singleton() {

}

public static Singleton getInstance() {

if (instance == null) {

synchronized (Singleton.class) {

if (instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

}

123456789101112131415161718

双重检验锁机制的单例模式,线程安全且在多线程情况下能保持高性能。

注意Singleton类的静态变量instance使用volatile修饰,用于禁止指令重排

//instance = new Singleton(); 分为下面三步执行(伪代码)

memory = allocate;//1.分配对象内存空间

initialization(memory);//2.初始化对象

instance = memory;//3.设置instance指向刚分配并初始化完毕的内存地址,此时instance != null

1234

步骤2和步骤3不存在数据依赖关系,而且无论重排前还是重排后程序的执行结果在单线程中并没有改变,因此这种重排优化是允许的。所以指令重排只会保证串行语义的执行的一致性(单线程),但不会关心多线程间的语义一致性。

memory = allocate;//1.分配对象内存空间

instance = memory;//3.设置instance指向刚分配的内存地址,此时instance != null。

initialization(memory);//2.初始化对象

123

所以在执行的时候第二步和第三步完全有可能颠倒顺序(伪代码如上),所以当一个线程访问instance不为null时,由于instance实例未必已经初始化完成,也就造成了线程安全问题。所以instance变量需要使用volatile关键字修饰,用于禁止指令重排

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马