簡要概述java記憶體模型,以及volatile關鍵字,javavolatile
如果我們要想深入瞭解Java並發編程,就要先理解好Java記憶體模型。Java記憶體模型定義了多線程之間共用變數的可見度以及如何在需要的時候對共用變數進行同步。原始的Java記憶體模型效率並不是很理想,因此Java1.5版本對其進行了重構,現在的Java8仍沿用了Java1.5的版本。
在java中每個線程都有一塊本地記憶體,而本地記憶體存放的變數是主記憶體的副本。相當於線上程啟動時候線程會複製主記憶體的變數到自己的本地記憶體。當本地記憶體變數改變時候就同步到主記憶體。如果有多個變數線程共用變數,這時候主記憶體又會重新整理同步所有線程的變數。而這種同步並不是即時的。
如何和證明每個線程內部都有一份主記憶體副本?
下面有段代碼
package com.mylienkd;public class MyThread implements Runnable {private Integer nubmer=0;@Overridepublic void run() {while(true){if(nubmer>1){System.out.println(Thread.currentThread()+"子線程迴圈結束");break;}}}public void setNubmer(Integer nubmer) {this.nubmer = nubmer;}public static void main(String[] args) throws Exception {MyThread thread=new MyThread();new Thread(thread).start();//睡眠1sThread.sleep(1000);thread.setNubmer(10);//睡眠3sThread.sleep(3000);System.out.println("主線程結束");}}
在此運行此代碼得到如下結果
仔細觀察代碼以及結果可以發現,在主線程更改變數nubmer為10後,主線程執行結束,但是控制台並沒退出一直在執行。
這是因為子線程並沒有退出迴圈。因為子執行緒區域記憶體的number為0,主記憶體中的值並沒有重新整理到子線程中的本記憶體的所以才會出現這種狀態。
如何解決此方法。java為了避免這種情況提供了關鍵字volatile ,在number變數上加上volatile關鍵字
private volatile Integer nubmer=0;
運行此代碼得到結果
可以看到此代碼在主線程退出前,子線程就先退出了迴圈。這是因為volatile關鍵字即時更新此變數。在number變數更改時,就同步重新整理更改其他線程的副本變數。
在很多地方叫做volatile關鍵字解決可見度。