这个问题仅涉及内存可见性,不会发生在之前和发生之后.
Java中有四种方法可以保证一个线程中的内存更改对另一个线程可见. (参考
http://gee.cs.oswego.edu/dl/cpj/jmm.html)
>写入线程释放同步锁,读取线程随后获取相同的同步锁.
>如果一个字段被声明为volatile,则在写入程序线程执行任何进一步的内存操作之前,写入该文件的任何值都会被刷新并使其可见(即,为了手头的目的,它会立即刷新).
>线程第一次访问对象的字段时,它会看到字段的初始值或自某个其他线程写入的值.
>当一个线程终止时,所有写入的变量都被刷新到主存储器.
根据Java Concurrency in Practice,关于这些问题的圣经:
The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after readin the volatile variable.
挥发性的问题
这是否意味着JVM实际上跟踪了易失性变量读写,以便知道如何将内存从A刷新到B而不是A到C?所以A写入变量,后来C从变量读取,然后B从变量读取,刷新是在A和B以及A和C之间的每个线程基础上完成的,而不是B和C?或者,它是否暗示所有缓存的内存都被刷新,无论线程如何?只是刷新了volatile变量,还是所有缓存的内存?
同步问题
对于synchronized关键字刷新,它表示只有锁内部更新的内存才能保证发布到其他线程.这意味着在下面的代码中,两个运行method()的线程,保留synchronized块会将staticVar2刷新到另一个线程,但不是staticVar1,这是正确的吗?
此外,在method2()中,如果另一个线程正在执行method(),则可以导致在发生问题之前发生 – 遇到问题.但是,问题在于可见性.如果线程A执行方法,那么后来的线程B执行method2(),是从A到B发布的staticVar2的值,即使这两个线程没有通过同一个锁同步?
static int staticVar1, staticVar2;
void method() {
staticVar1++;
synchronized (lock) {
staticVar2++;
}
}
void method2() {
synchronized (differentLock) {
staticVar2++;
}
}
静态问题
在我看来,如果staticVar1永远不会更新到其他线程,那么任何程序中的所有静态变量都需要一个volatile声明,或者只能在synchronized块中访问.这似乎相当苛刻,但它是否正确?我确定在我的时间里看到了很多不同步的静态变量.
综上所述
>易失性读写会将所有内存刷新到所有线程,还是仅在两个访问线程之间?无论哪个答案,是所有内存都刷新了还是只有易变量?
>退出同步块时,或者只是块内更改的内存,是否刷新了内存?如果没有刷新所有内存,则线程同步的锁定对象是否必须相同才能看到该值(即锁定对象是否对内存可见性有任何影响)?
>是否必须同步两个线程访问的所有静态变量?