使用synchronized的兩條規定:java
也就是說使用volatile關鍵字在讀和寫操做時都會強迫從主內存中獲取變量值。
下圖是使用volatile寫操做的示意圖併發
使用volatile寫操做前會插入一條StoreStore指令來禁止在volatile寫以前的普通寫對volatile寫的指令重排序優化,在寫以後會插入一條StoreLoad屏障指令來防止上面的volatile寫操做和下面可能有的讀或者寫進行指令重排序。
下圖是volatile讀操做示意圖優化
下面看一段演示代碼ui
@Slf4j public class CountExample4 { // 請求總數 public static int clientTotal = 5000; // 同時併發執行的線程數 public static int threadTotal = 200; public static volatile int count = 0; public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal ; i++) { executorService.execute(() -> { try { semaphore.acquire(); add(); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("count:{}", count); } private static void add() { count++; // 一、count // 二、+1 // 三、count } }
咱們屢次運行個這段代碼,發現結果並非咱們預期5000,volatile只能保證可見性並不能保證原子性。spa
一般來講使用volatile須要具有兩個條件線程
因此volatile很是適合用做狀態標記量,好比作爲線程是否被初始化。還有就是用double check 我以前的博客就提到的單例模式中就使用了volatile來作double check 雙重檢查實現單例。code