Java內(nèi)存可見(jiàn)性

經(jīng)常訪問(wèn)的變量會(huì)從主存讀取到線程的高速緩沖區(qū),導(dǎo)致不同線程間對(duì)數(shù)據(jù)的修改不能及時(shí)同步:


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();
    }
}

上方代碼直接運(yùn)行,t1線程始終無(wú)法讀到main線程對(duì)值的修改正常結(jié)束。

要想同步t1和main的值。

  • 可以在變量前加volatile(易變的)關(guān)鍵字,使得每個(gè)線程對(duì)變量的訪問(wèn)不生成高速緩存,必須去主存讀取和修改(保證了可見(jiàn)性但降低了性能)。
  • 遇到同步代碼塊或者同步方法(synchronized),也會(huì)更新線程私有高速緩沖內(nèi)存的值,println是一個(gè)同步方法,上方注釋//System.out.println("this can stop!");打開(kāi)會(huì)導(dǎo)致更新緩沖區(qū)的值。
  • 若上方TimeUnit.MILLISECONDS.sleep(10); 修改為TimeUnit.MILLISECONDS.sleep(1);也會(huì)成功停止,因?yàn)楦咚倬彌_還未形成,t1還是從主存中去讀取的變量值。

注:
volatile和synchronized都可以實(shí)現(xiàn)線程間的可見(jiàn)性,但volatile沒(méi)有上鎖步驟,在實(shí)現(xiàn)可見(jiàn)性方面更輕量,但不能保證原子性。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容