線程安全性--volatile

volatile:當多個線程進行操作共享數據時,可以保證內存中的數據是可見的;

@Slf4j
public class MyVolatile {

    public static void main(String[] args) {
        ThreadRun threadRun = new ThreadRun();
        new Thread(threadRun).start();

        log.info("begin----flag:{}",threadRun.flag);
        while (true){
            if (threadRun.flag){
                log.info("main ---flag:{}",threadRun.flag);
                break;
            }
        }
    }

    static class ThreadRun implements Runnable{
        private boolean flag = false;

        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            flag  = true;
            log.info("threadRun----flag:{}",flag);
        }

        public boolean isFlag() {
            return flag;
        }

        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    }
}

運行結果如下圖所示,程序一種在運行,無法結束。

代碼分析:主線程main運行之後,開啓了另外一個線程ThreadRun,ThreadRun線程睡眠1000毫秒之後,將flag標記變爲true。但是對於主線程來說,flag標記一直是false,ThreadRun改變後的flag的值對於主線程來說是不可見的,因此主線程一直在while循環中。

接下來再看使用了volatile關鍵字之後:

 static class ThreadRun implements Runnable{
        private volatile boolean flag = false;
		//其他都一樣
}

代碼運行結果發生了改變。

volatile關鍵字比較適用於上述這種情況。但是對於計數這種情況來說,並不適用

public class VolatileTest {
    //請求總數
    private static int clientTotal = 5000;
    //同時允許執行的線程總數
    private static int threadTotal = 200;
    private static volatile int count = 0;

    public static void main(String[] args) throws InterruptedException {
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i=0;i<clientTotal;i++){
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        count++;
                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println("count="+count);
    }
}

雖然count使用了volatile修飾,但程序運行的結果並不是我們預想的5000。具體原因可參考另一篇博文線程安全性--atomic中的內容進行理解。 本文只是覺得第一個例子很好的說明了volatile的使用場景。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章