Java内存可见性

作者: Chermack | 来源:发表于2020-10-05 20:26 被阅读0次

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

    
    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内存可见性

        本文链接:https://www.haomeiwen.com/subject/qmoauktx.html