所有线程都可以看到volatile变量的突变吗?

时间:2015-06-12 10:16:19

标签: java multithreading volatile

假设我对MyClass有一个易变的引用c,而MyClass有一个整数字段x。如果一个线程更改了x的值,那么新值是否会保证对所有其他线程可见,或者x是否也必须是volatile?

换句话说,以下示例是否保证打印2?

public class MyClass {

private static volatile MyClass c;

private int x = 1;

public static void main(String[] args) {
    c = new MyClass();
    Thread thread = new Thread(new Runnable() {

        @Override
        public void run() {
            c.x = 2;

        }
    });
    thread.start();
    try {
        thread.join();
        System.out.println(c.x);
    } catch (InterruptedException ex) {
        //
    }


}

如果没有,如果我想操作一个我无法控制的源代码的对象,比如Collection,该怎么办?如何确保对所有线程都可以看到Collection对象的更改?

2 个答案:

答案 0 :(得分:2)

对于您的示例,Varialbe x也必须是易变的。

  

如果是这样,如果我想操作源代码为I的对象该怎么办?   不管,如收藏?我该如何确保更改   所有线程都可以看到集合对象吗?

要查看集合中的更改(假设它不是并发集合,假设它是一个普通的ArrayList),您应该自己提供一个监视器。

Object monitor = new Object();

synchronized(monitor) {
   // change collection
}

synchronized(monitor) {
   // read collection
}

如果读取和写入操作将在监视器上同步,它们将正常工作。但是,如果您有无法控制的代码,并且此代码在没有同步的情况下修改集合,则无法执行任何操作。

问题2:即使在监视器上进行读/写同步,如果在一个线程中迭代集合并在另一个线程中修改它,你仍然可以得到一些ConcurrentModificationExceptions。因此,我的示例中的读取不是参考读取,而是读取的值。

答案 1 :(得分:1)

对于你的第一个问题,是的。 Volatile确保其他线程的读操作可以看到对volatile字段的写入。然而,它不会级联,因此volatile不适合所有用例(即,仅仅因为引用是volatile,并不意味着引用对象的所有字段都会神奇地变得易变)。

在大多数情况下,您需要synchronize访问权限,以确保后续读取可以看到所有写入。