Java内存可见性

经常访问的变量会从主存读取到线程的高速缓冲区,导致不同线程间对数据的修改不能及时同步:


import java.util.concurrent.TimeUnit;

class TObject{
    public boolean b = false;
}

public class VisibilityTest {
    static boolean flag = true;
    static int num = 1;
    static String s = "a";
    static TObject tObject = new TObject();
    static Object object;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (flag) {
                if (num==100) break;
                if (s.equals("b")) break;
                if (tObject.b) break;
                if (object!=null) break;
//                System.out.println("this can stop!");
            }
        });
        t1.start();
        TimeUnit.MILLISECONDS.sleep(10);
        flag = false;
        num = 100;
        s = "b";
        tObject.b = true;
        object=new Object();
    }
}

上方代码直接运行,t1线程始终无法读到main线程对值的修改正常结束。

要想同步t1和main的值。

  • 可以在变量前加volatile(易变的)关键字,使得每个线程对变量的访问不生成高速缓存,必须去主存读取和修改(保证了可见性但降低了性能)。
  • 遇到同步代码块或者同步方法(synchronized),也会更新线程私有高速缓冲内存的值,println是一个同步方法,上方注释//System.out.println("this can stop!");打开会导致更新缓冲区的值。
  • 若上方TimeUnit.MILLISECONDS.sleep(10); 修改为TimeUnit.MILLISECONDS.sleep(1);也会成功停止,因为高速缓冲还未形成,t1还是从主存中去读取的变量值。

注:
volatile和synchronized都可以实现线程间的可见性,但volatile没有上锁步骤,在实现可见性方面更轻量,但不能保证原子性。

你可能感兴趣的:(Java内存可见性)