您好,登錄后才能下訂單哦!
這篇文章主要講解了“Java volatile關鍵字的特性是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java volatile關鍵字的特性是什么”吧!
volatile是Java中的關鍵字,用來修飾會被不同線程訪問和修改的變量。
volatile是Java虛擬機提供的輕量級的同步機制,它有三個特性:
(1)保證可見性
(2)不保證原子性
(3)禁止指令重排
volatile保證可見性
Java內存模型(JMM)定義了一組規則、規范,規定了程序中各個變量的訪問方法。JMM關于同步的規定:
(1)線程解鎖前,必須把共享變量的值刷新回主內存;
(2)線程加鎖前,必須讀取主內存的最新值同步到自己的工作內存;
(3)加鎖解鎖必須是同一把鎖;
說明:由于JVM運行程序的實體是線程,創建每個線程時,JMM會為其創建一個工作內存(也稱棧空間),工作內存是每個線程的私有數據區域。
Java內存模型規定所有變量都存儲在主內存,主內存是共享內存區域,所有線程都可以訪問。
但是線程對變量的操作(讀取、賦值等)必須在工作內存中進行。因此首先要將變量從主內存拷貝到自己的工作內存,然后對變量進行操作,操作完成后再將變量寫會主內存中。
舉例說明:
(1)火車票賣票系統還剩下一張票,并已經刷入到主內存中:ticketNum = 1;
(2)此時有3個用戶在同時購買票,3個線程都讀入了目前的票數,ticketNum=1,那么線程就會繼續進入購買流程。
(3)假設其中一個線程先搶占了CPU資源,先買到票,并將自己的工作內存中的ticketNum值改為0,ticketNum=0,然后再寫回到主內存。
這時,由于一個線程的用戶已經買到了票,那么其他用戶的線程應該不能再繼續進入購買票的流程了,因此需要系統通知到其他線程 ticketNum=0 這個消息。如果可以達到這樣的效果,可以理解為 具有可見性。
無可見性代碼演示:
@Test public void test1() { DataDemo dataDemo = new DataDemo(); RunThread runThread = new RunThread(dataDemo); runThread.start(); while (dataDemo.getNumber() == 0) { } System.out.println("具有可見性驗證通過"); } public class DataDemo { private int number = 0; public void add() { this.number = this.number + 10; } public int getNumber() { return number; } } public class RunThread extends Thread { private DataDemo dataDemo; public RunThread(DataDemo dataDemo) { this.dataDemo = dataDemo; } @Override public void run() { System.out.println("線程[" + Thread.currentThread().getName() + "] 正在執行"); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } dataDemo.add(); System.out.println("線程[" + Thread.currentThread().getName() + "]更新后,number值為:" + dataDemo.getNumber()); } }
執行結果:
線程[Thread-0] 正在執行
線程[Thread-0]更新后,number值為:10
結果分析:
可以看出子線程啟動后將number值改為了10,雖然已經改為了非0,但是主線程仍然一直處于while循環中,因此此時number不具有可見性,系統不會主動通知主線程number值修改。
原理說明:
這個問題其實就是私有堆棧中的值和公共堆棧中的值不同步造成的。解決這樣的問題就要使用 volatile 關鍵字了,它主要的作用就是當線程訪問number這個變量時,強制性從公共堆棧中進行取值。
可見性代碼演示:
@Test public void test1() { DataDemo dataDemo = new DataDemo(); RunThread runThread = new RunThread(dataDemo); runThread.start(); while (dataDemo.getNumber() == 0) { } System.out.println("具有可見性驗證通過"); } public class DataDemo { // 給變量 number 添加 volatile 關鍵字修飾 volatile private int number = 0; public void add() { this.number = this.number + 10; } public int getNumber() { return number; } } public class RunThread extends Thread { private DataDemo dataDemo; public RunThread(DataDemo dataDemo) { this.dataDemo = dataDemo; } @Override public void run() { System.out.println("線程[" + Thread.currentThread().getName() + "] 正在執行"); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } dataDemo.add(); System.out.println("線程[" + Thread.currentThread().getName() + "]更新后,number值為:" + dataDemo.getNumber()); } }
執行結果:
線程[Thread-0] 正在執行
線程[Thread-0]更新后,number值為:10
具有可見性驗證通過
結果分析:
通過對變量number變量添加了volatile關鍵字修飾,可以看出子線程啟動后將number值改為了10,隨后主線程跳出了while循環,輸出了“具有可見性驗證通過”,說明此時number具有可見性。
原理說明:
通過使用 volatile 關鍵字,強制從公共內存中讀取變量的值,內存結構如圖:
感謝各位的閱讀,以上就是“Java volatile關鍵字的特性是什么”的內容了,經過本文的學習后,相信大家對Java volatile關鍵字的特性是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。