[Java] Volatile keyword的介绍

阅读时间: 10分钟

Volatile关键字 可以确保在应用程式中的可见性,支持变量直接写入到主记忆体(main memory)。

来自《Thinking in Java , edtion 4》的解释

The volatile keyword also ensures visibility across the application. If you declare a field to >be volatile, this means that as soon as a write occurs for that field, all reads will see the >change. This is true even if local caches are involved—volatile fields are immediately written >through to main memory, and reads occur from main memory.

Volatile的主要功能:
第一:提供可见性
当一个变量的前面被加上Volatile后,当它的被修改就会即时被更新到主记忆体(main memory)。
当有其他thread想存取这变量的最新值,都可以在主记忆体(main memory)中看到。
要做到这效果还有其他方法,就是利用Synchronized + Lock来实现。
但不在这里详述,会再另一篇文章作讲解。

public class WorkerThread extends Thread {    private boolean isRunning = true;    @Override    public void run() {        while (isRunning) {            // execute a task        }    }    public void stopWorker() {        isRunning = false;    }}

在上面的例子可以看到它有两个tasks分别是run() 和stopWorker() 。
变量isRunning 的预设值true,所以可以执行run() 内的动作。
而stopWorker() 则是可以控制能否执行run() ,因为它可以修改isRunning 的值。
但在这个例子中,即使修改了isRunning 的值为false,run()都仍然有机会执行。
重点在于run()能否在主记忆体中获得最新的isRunning 的值。
为了确保run()能获得最新的isRunning 的值,我们可以利用Volatile关键字来解决。

在变量isRunning前加上volatile:

public class WorkerThread extends Thread {    private volatile boolean isRunning = true;    @Override    public void run() {        while (isRunning) {            // execute a task        }    }    public void stopWorker() {        isRunning = false;    }}

第二:保证初始化对象时的次序(happens-before relationship)

public class MyWorker {  private int workerNumber;  public MyWorker (int workerNumber) {    this.workerNumber = workerNumber;  }  public int getWorkerNumber () {    return workerNumber;  }}

在上面的例子,我们可以实例化MyWorker class (同时假设这是其中一个Thread,名字叫Thread 1)

MyWorker workerInstance = new MyWorker (1);

当执行之上的code时,JVM 会依以下次序操作:
1: 分配记忆体的空间
2: 将分配到的记忆体的空间(记忆体的空间的地址)给予实例workerInstance
(workerInstance 不再是null了)
3: 将值写入workerInstance

不过在第2个与第3个步骤之间会有机会遇到其他Thread正在执行以下程式:

if(workerInstance!= null){  System.out.println(workerInstance.getValue());}

所以最后由Thread 1实例化MyWorker class的结果不是1。

为了解决上述的问题,我们可以在变量workerNumber前加上volatile关键字。
可以保证JVM只能在完成所有写入程序后(完成第3个步骤后)才能读取workerInstance的值。

public class MyWorker {  private volatile int workerNumber;  public MyWorker (int workerNumber) {    this.workerNumber = workerNumber;  }  public int getWorkerNumber () {    return workerNumber;  }}

参考文章/网站/书本:

volatile keyword
https://www.byteslounge.com/tutorials/java-volatile-example

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章