首頁常見問題正文

實現(xiàn)可見性的方法有哪些?

更新時間:2023-07-25 來源:黑馬程序員 瀏覽量:

IT培訓(xùn)班

  在Java中,實現(xiàn)可見性(visibility)的主要方法是使用關(guān)鍵字volatile和使用鎖(如synchronized關(guān)鍵字或 java.util.concurrent包中的鎖)來確保對共享變量的修改在多線程環(huán)境中能夠正確地被其他線程所觀察到。

  下面詳細(xì)說明這兩種方法,并附帶代碼演示。

  1.使用volatile關(guān)鍵字:

  volatile是一種輕量級的同步機(jī)制,用于告訴JVM對被修飾的變量不進(jìn)行緩存,直接從主內(nèi)存中讀取和寫入數(shù)據(jù)。這樣可以確保當(dāng)一個線程修改了變量的值時,其他線程能夠立即看到這個變化,而不是使用緩存中的舊值。

public class VolatileVisibilityExample {
    private volatile boolean flag = false;

    public void setFlag(boolean value) {
        flag = value;
    }

    public void checkFlag() {
        while (!flag) {
            // Busy waiting until the flag becomes true
        }
        System.out.println("Flag is now true!");
    }

    public static void main(String[] args) {
        VolatileVisibilityExample example = new VolatileVisibilityExample();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            example.setFlag(true);
        }).start();

        new Thread(() -> {
            example.checkFlag();
        }).start();
    }
}

  在上面的例子中,我們創(chuàng)建了一個VolatileVisibilityExample類,其中的flag變量被聲明為volatile。第一個線程在啟動后會等待1秒鐘然后將flag設(shè)置為true,而第二個線程在flag變?yōu)閠rue之前會一直進(jìn)行忙等待(busy waiting)。由于flag是volatile的,第二個線程能夠看到第一個線程對flag的修改,并在flag變?yōu)閠rue時結(jié)束忙等待。

  2.使用鎖:

  另一種實現(xiàn)可見性的方法是使用鎖,通過synchronized關(guān)鍵字或者java.util.concurrent包中的鎖機(jī)制來保護(hù)對共享變量的訪問。

public class LockVisibilityExample {
    private boolean flag = false;
    private final Object lock = new Object();

    public void setFlag(boolean value) {
        synchronized (lock) {
            flag = value;
        }
    }

    public void checkFlag() {
        synchronized (lock) {
            while (!flag) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("Flag is now true!");
    }

    public static void main(String[] args) {
        LockVisibilityExample example = new LockVisibilityExample();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            example.setFlag(true);
            synchronized (example.lock) {
                example.lock.notifyAll();
            }
        }).start();

        new Thread(() -> {
            example.checkFlag();
        }).start();
    }
}

  在上面的例子中,我們創(chuàng)建了一個LockVisibilityExample類,其中使用了一個名為lock的對象作為鎖。在setFlag和checkFlag方法中,我們使用synchronized關(guān)鍵字來保護(hù)對flag的訪問。第一個線程設(shè)置flag為true并通過synchronized塊的notifyAll()方法通知第二個線程,而第二個線程則在flag變?yōu)閠rue之前一直等待,并在被通知后結(jié)束等待。

  這兩種方法都可以實現(xiàn)可見性,但使用volatile更為簡單和輕量級。然而,在某些情況下,使用鎖可能會更有優(yōu)勢,例如需要進(jìn)行更復(fù)雜的操作或需要更精細(xì)地控制對共享資源的訪問。

分享到:
在線咨詢 我要報名
和我們在線交談!