Skip to main content

说说并发编程 volatile

Java volatile关键字是用来保证变量的线程可见性。到底什么是线程的可见性呢?准确地讲,每次读取volatile变量要从主内从中读取,而不是从CPU cache中读取;写一个volatile变量,要直接写到主内存,而不仅仅是CPU cache。

Java 5 引入了volatile,就保证了读写都要从主内存中取值。下边详细介绍一下:

线程可见性
在多线程应用程序中, 当线程操作非volatile变量,每个线程需要复制变量从主内存到 CPU缓存中,出于性能方面的设计。如果你的计算机包含多个 CPU,每个线程可能会在不同的 CPU 上运行。这意味着,每个线程可能会将变量复制到不同的 Cpu 的 CPU 缓存。如下所示 ︰
字节码

非volatile变量不保证从主内存中立即读取数据或将数据从CPU 缓存中直接写入到主内存。如果多线程操作一个共享变量的话,就会出现如下的问题:

[java]
public class SharedObject {

public volatile int counter = 0;

}

[/java]

想象一下,如果只有线程1更新counter变量,但是线程1和线程2却可能拿到的不是最新的值。如果没用申明volatile,JVM并不保证counter变量的值马上写回到主内存中,那就意味着CPU cache中的值并不是最新的值。如下图所示:
字节码

这就是线程可见性的问题。线程2并没有实时看到最新的值,因为JVM会先从CPU cache中读取值。

如果申明为volatile,则线程读取值,必须从主内存中读取,写值,必须写到主内存中,这就保证了所有的值对于线程是可见的。但是这不能说明它是线程安全的。这是两个不同的概念。

例子
[java]
package com.learn.core.ch02;

public class VolatileTest {

private int count = 0;

public static void main(String[] args) throws InterruptedException {
while (true) {
VolatileTest test = new VolatileTest();
test.setCount(0);
Thread[] ts = new Thread[2];
for (int i = 0; i < 2; i++) {
ts[i] = new Thread(new MyRun(test, i));
ts[i].start();
}

for (Thread t : ts) {
t.join();
}
Thread.sleep(2);

}
}

public static class MyRun implements Runnable {

private VolatileTest test;
private int index;

public MyRun(VolatileTest test2, int index) {
this.test = test2;
this.index = index;
}

@Override
public void run() {
if (index == 0) {
test.increment();
} else {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (test.getCount() == 0) {
System.out.println(Thread.currentThread().getName() + "—–" + test.getCount());
}
}
}

public int getCount() {
return count;
}

public void increment() {
count++;
}

public void setCount(int count) {
this.count = count;
}

}

[/java]
Thread-10181—–0
Thread-10957—–0
Thread-10959—–0
Thread-11643—–0
Thread-12177—–0
Thread-12269—–0
Thread-12345—–0
Thread-12929—–0
Thread-13221—–0
加上volatile关键字,就可以保证永远拿到最新的值,前提是写的线程先执行。

在 “说说并发编程 volatile” 上有 2 条评论

  1.      _∧_∧_
         ((∀`/  )
        /⌒   /
       /(__ノ\_ノ
      (_ノ |||
    好棒啊~~赞~~~ 
     ∧_∧ ∧_∧
    (( ・∀・ ))・∀・) )
    `\   ∧   ノ
     /  |/  |
    (_ノ_)_ノL_)

发表评论

电子邮件地址不会被公开。