假设我对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对象的更改?
答案 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
访问权限,以确保后续读取可以看到所有写入。