1. 程式人生 > >Java執行緒面試題(03) Java中的volatile如何工作? Java中的volatile關鍵字示例

Java執行緒面試題(03) Java中的volatile如何工作? Java中的volatile關鍵字示例

本文為本博主翻譯,未經允許,嚴禁轉載!!!

簡介

什麼是Java中的volatile變數以及何時使用Java中的volatile變數是一道Java面試中經常被問及的多執行緒訪問問題。儘管許多程式設計師知道什麼是volatile變數,但是他們在回答第二部分問題什麼地方使用volatile變數時失敗,因為大部分人對Java中volatile變數並沒有一個清晰的理解和應用。在本教程中,我們將通過提供一個Java中volatile變數的簡單示例來解決這個問題,並討論在Java中使用volatile變數的一些情況。無論如何,Java中的volatile關鍵字被用作Java編譯器和Thread的指示器:它不會快取這個變數的值,並且總是從主記憶體中讀取它。所以如果你想共享任何變數,其中讀寫操作是通過實現原子的。比如讀取和寫入一個int或一個布林變數,你可以宣告他們作為volatile變數。

Java 5除了自動裝箱,列舉,泛型和可變引數等主要變化外,Java引入了一些Java記憶體模型(JMM)的變化,它保證了一個執行緒的變好對另一個執行緒的可視性,也被解釋為“發生之前”來解決記憶體的寫入問題。在一個執行緒中發生的記憶體寫入會“洩漏”,並被另一個執行緒看到。
Java volatile關鍵字不能與方法或類一起使用,只能與變數一起使用。 Java可變關鍵字還保證可見性和排序,Java 5之後, 寫入任何volatile變數發生在任何讀取到volatile變數之前。順便說一句,使用volatile關鍵字還可以防止編譯器或JVM對程式碼進行重新排序或將其從同步障礙中移走。

Java中的volatile變數示例

為了理解java中的volatile關鍵字的例子,我們回到Java中的Singleton模式。

/**
 * Java program to demonstrate where to use Volatile keyword in Java. 
 * In this example Singleton Instance is declared as volatile variable to ensure 
 * every thread see updated value for _instance. 
 * @author Javin Paul
 */
public class Singleton {
	private static volatile Singleton _instance;

	// volatile variable
	public static Singleton getInstance() {
		if (_instance == null) {
			synchronized (Singleton.class) {
				if (_instance == null)
					_instance = new Singleton();
			}
		}
		return _instance;
	}
}
如果仔細檢視程式碼,您將能夠弄清楚:
1)我們只是一次建立例項
2)在第一次請求來的時候建立例項。


如果我們不定義_instance為volatile變數,則建立Singleton的例項的Thread不能與其它執行緒通訊,告知該例項已經被建立直到它退出Singleton同步塊,所以如果執行緒A正在建立Singleton例項並且隨後執行緒切換,所有其他執行緒將不能將_instance的值看作非null,並且它們將認為它仍然為空。

為什麼?因為讀執行緒沒有進行任何鎖定,直到寫執行緒退出同步塊,記憶體將不會同步,_instance的值不會在主記憶體中更新。在Java中使用Volatile關鍵字時,這是由Java自己處理的,所有讀者執行緒都可以看到這些更新。

因此,除了Java中的同步關鍵字文章中相關總結外,volatile關鍵字還用於線上程之間傳遞記憶體內容。

我們來看看Java中volatile關鍵字的另一個例子

在寫遊戲的大部分時間裡,我們使用一個變數bExit來檢查使用者是否按下了退出按鈕,這個變數的值在事件執行緒中被更新,並在遊戲執行緒中被檢查過,所以如果我們沒有在這個變數中使用volatile關鍵字,Game Thread可能會錯過來自事件處理程式執行緒的更新,如果它在Java中不同步。 Java中的volatile關鍵字保證volatile變數的值總是從主記憶體中讀取,而Java Memory模型中的“happen-before”關係將確保記憶體的內容將被傳送到不同的執行緒。

private boolean bExit;

while(!bExit) {
   checkUserPosition();
   updateUserPosition();
}
在這個程式碼示例中,一個執行緒(遊戲執行緒)可以快取“bExit”的值,而不是每次從主記憶體獲取它,如果在任何其他執行緒(事件處理執行緒)之間改變值;它不會被這個執行緒看到。在java中使布林變數“bExit”變成volatile可以確保不會發生這種情況。
為了真正理解這個複雜的概念, 我還建議您閱讀Brian Goetz撰寫的Java Concurrency in Practice書中關於volatile變數的主題。

何時在Java中使用volatile變數

在volatile關鍵字的學習中最重要的一點是瞭解何時在Java中使用volatile變數。許多程式設計師知道什麼是volatile變數,它是如何工作的,但他們從來沒有真正使用volatile來實現任何實際目的。這裡有幾個示例演示何時在Java中使用Volatile關鍵字:
1)如果你想以原子方式讀寫long型別變數和double型別變數,可以使用Volatile變數。 long和double都是64位資料型別,預設情況下,long和double的寫入不是原子和平臺依賴。許多平臺在長和雙變數2步執行寫操作,在每一步寫32位,由於這可能使一個執行緒看到從兩個不同的寫32位。您可以通過在Java中使用long和double變數volatile來避免此問題。
2)在某些情況下,volatile可以用作實現Java同步的一種替代方法,如Visibility。用volatile變數,保證所有讀寫器執行緒在寫操作完成後都會看到volatile變數的更新值,而不用volatile關鍵字,不同的讀執行緒可能會看到不同的值。
3)volatile變數可用於通知編譯器一個特定的欄位被多個執行緒訪問,這將阻止編譯器進行任何重新排序或在多執行緒環境中不希望的任何型別的優化。如果沒有volatile變數,編譯器可以重新排序程式碼,可以自由地快取volatile變數的值,而不是總是從主記憶體中讀取資料。就像下面沒有volatile變數的例子可能會導致無限迴圈

private boolean isActive = thread; 
public void printMessage(){ 
    while(isActive) { 
	    System.out.println("Thread is Active"); 
    } 
} 
如果沒有volatile修飾符,則不能保證一個執行緒從其他執行緒看到isActive的更新值。編譯器還可以自由快取isActive的值,而不是在每次迭代中從主儲存器中讀取。通過使isActive成為一個volatile變數,可以避免這些問題。

4)另一個可以使用volatile變數的地方是在Singleton模式下修復雙重檢查的鎖定。

Java中的Volatile關鍵字的重點

1)Java中的volatile關鍵字只適用於一個變數,使用volatile關鍵字和class和method是非法的。
2)Java中的volatile關鍵字保證volatile變數的值總是從主記憶體中讀取,而不是從Thread的本地快取中讀取。
3)在Java中,對於使用Java volatile關鍵字(包括長變數和雙變數)宣告的所有變數,讀寫操作是原子操作。
4)在變數Java中使用volatile關鍵字可降低記憶體一致性錯誤的風險,因為在Java中對volatile變數的任何寫入都會與隨後的同一變數的讀取之間建立一個happen-before關係。
5)從Java 5,volatile變數的更改對其他執行緒始終可見。更重要的是,這也意味著當一個執行緒在Java中讀取一個volatile變數時,它不僅會看到volatile變數的最新變化,而且還會看到導致變化的程式碼的副作用。
6)即使沒有在Java中使用volatile關鍵字,讀取和寫入也是原子參考變數是大多數原始變數(除了long和double之外的所有型別)。
7)對Java中的volatile變數的訪問從來沒有機會阻止,因為我們只是做一個簡單的讀或寫操作,所以不像一個同步塊,我們永遠不會持有任何鎖或等待任何鎖。
8)作為物件引用的Java volatile變數可能為空。
9)Java volatile關鍵字並不意味著原子化,它在宣告volatile之後會是原子的常見誤解,為了使操作原子化,還需要使用Java中的同步方法或塊來確保獨佔訪問。
10).如果多個執行緒之間不共享變數,則不需要在該變數中使用volatile關鍵字。

Java中的synchronized和volatile關鍵字之間的區別

volatile和synchronized之間的區別, 是另一個流行的關於多執行緒和併發訪問的核心Java面試問題。記住volatile不是synchronized關鍵字的替代品,但可以在某些情況下用作替代品。 這裡列出了一些Java中volatile和synchronized關鍵字之間的差異:
1) volatile關鍵字是一個欄位修飾符,synchronized修改程式碼塊和方法。
2) synchronized獲取並釋放監視器的鎖, volatile關鍵字不需要這個鎖。
3)Java中的執行緒可以被阻塞,以便在同步的情況下等待任何監視器,這與Java中的volatile關鍵字不同。
4)在Java中,synchronized方法相比volatile關鍵字, 會影響效能
5) 由於Java中的volatile關鍵字只同步執行緒記憶體和“主”記憶體之間的一個變數的值,synchronized同步執行緒記憶體和“主”記憶體之間的所有變數的值,並鎖定和釋放監視器。由於這個原因,Java中的synchronized關鍵字可能比volatile更具開銷。
6)您不能同步空物件,但Java中的volatile變數可能為空。
7) 從Java 5寫入volatile欄位與監視器釋放具有相同的記憶效應,並且從易失性欄位讀取具有與監視器獲取相同的記憶效應

簡而言之,Java中的volatile關鍵字不是synchronized塊或方法的替代,但在某些情況下非常方便,可以節省Java中使用同步帶來的效能開銷。如果你想了解更多關於易失性的內容,我也建議在Java記憶體模型的常見問題上進行解釋。

原文連結

相關推薦

Java執行試題(03) Javavolatile如何工作Javavolatile關鍵字示例

本文為本博主翻譯,未經允許,嚴禁轉載!!! 簡介 什麼是Java中的volatile變數以及何時使用Java中的volatile變數是一道Java面試中經常被問及的多執行緒訪問問題。儘管許多程式設計師知道什麼是volatile變數,但是他們在回答第二部分問題什麼地方使用vo

Java執行試題(01) Java如何檢查一個執行是否擁特定物件的鎖

本文為本博主翻譯,未經允許,嚴禁轉載 簡介 考慮一個場景,在執行時你必須確認一個Java執行緒是否持有特定物件的鎖,例如,確認NewsReader執行緒是否持有NewsPaper物件的鎖?如果這個問題出現在任何核心的Java面試中,那麼我會自動假設可能有至少兩個答案,一個是

Java執行試題之程序和執行的區別

1.定義 程序:具有一定獨立功能的程式關於某個資料集合上的一次執行活動,程序是系統進行資源分配和排程的一個獨立單位. 執行緒:程序的一個實體,是CPU排程和分派的基本單位,它是比程序更小的能獨立執行的基本單位.執行緒自己基本上不擁有系統資源,只擁有一點在執行中必不可少的資源(如程式計數器,一

Java執行試題 Top 50

以上就是50道熱門的Java多執行緒和併發面試題啦。我沒有分享所有題的答案但給未來的閱讀者提供了足夠的提示和線索來尋找答案。如果你真的找不到某題的答案,聯絡我吧,我會加上去的。這篇文章不僅可以用來準備面試,還能檢查你對多執行緒,併發,設計模式和競態條件,死鎖和執行緒安全等執行緒問題的理解。我打算把這篇文章的問

【總結】53道JAVA執行試題

1) 什麼是執行緒? 執行緒是作業系統能夠進行運算排程的最小單位,它被包含在程序之中,是程序中的實際運作單位。程式設計師可以通過它進行多處理器程式設計,你可以使用多執行緒對運算密集型任務提速。比如,如果一個執行緒完成一個任務要100毫秒,那麼用十個執行緒完成改任務只需10毫秒。Java在語言層面

Java執行——試題 Top 50

不管你是新程式設計師還是老手,你一定在面試中遇到過有關執行緒的問題。Java語言一個重要的特點就是內建了對併發的支援,讓Java大受企業和程式設計師的歡迎。大多數待遇豐厚的Java開發職位都要求開發者精通多執行緒技術並且有豐富的Java程式開發、除錯、優化經驗,所以執行緒相關

Java執行試題 Top 50 (轉載)

  不管你是新程式設計師還是老手,你一定在面試中遇到過有關執行緒的問題。Java語言一個重要的特點就是內建了對併發的支援,讓Java大受企業和程式設計師的歡迎。大多數待遇豐厚的Java開發職位都要求開發者精通多執行緒技術並且有豐富的Java程式開發、除錯、優化經驗,所以執行緒相關的問題在面試中經常

50道Java執行試題

1) 什麼是執行緒? 執行緒是作業系統能夠進行運算排程的最小單位,它被包含在程序之中,是程序中的實際運作單位。程式設計師可以通過它進行多處理器程式設計,你可以使用多執行緒對 運算密集型任務提速。比如,如果一個執行緒完成一個任務要100毫秒,那麼用十個執行緒完成改任務只需10

Java執行試題合集(含答案)

下面是我自己收集整理的Java執行緒相關的面試題,可以用它來好好準備面試。 參考文件: 《Java核心技術 卷一》 Java執行緒面試題 Top 50:http://www.importnew.com/12773.html JAVA多執行緒和併發基礎面試問答: htt

Java執行 併發 鎖 Java執行試題 Top 50

1) 什麼是執行緒? 執行緒是作業系統能夠進行運算排程的最小單位,它被包含在程序之中,是程序中的實際運作單位。程式設計師可以通過它進行多處理器程式設計,你可以使用多執行緒對運算密集型任務提速。比如,如果一個執行緒完成一個任務要100毫秒,那麼用十個執行緒完成改任務只需10毫

2017年50道Java執行試題

 下面是Java執行緒相關的熱門面試題,你可以用它來好好準備面試。 1) 什麼是執行緒? 執行緒是作業系統能夠進行運算排程的最小單位,它被包含在程序之中,是程序中的實際運作單位。程式設計師可以通過它進行多處理器程式設計,你可以使用多執行緒對 運算密集型任務提速。比如,如果一個執行緒完成一個任務要100毫秒

Java執行試題Top50

不管你是新程式設計師還是老手,你一定在面試中遇到過有關執行緒的問題。Java語言一個重要的特點就是內建了對併發的支援,讓Java大受企業和程式設計師的歡迎。大多數待遇豐厚的Java開發職位都要求開發者精通多執行緒技術並且有豐富的Java程式開發、除錯、優化經驗,所以執行緒

java執行試題1

1.什麼是執行緒? 執行緒是一個程式不同的執行路徑 2.執行緒和程序的區別? 一個程序可以包含多個執行緒,cpu給程序分配給空間,而不會給執行緒分配空間,多個執行緒共享程序的空間和資源 3.在java

15個頂級Java執行試題及回答 / Java程式設計師面試的多執行問題

http://wenku.baidu.com/link?url=-7RVShQCzkHaRbyPdGP-oeVXgZ7t4mS2oqXevpzweesI_Heof5zqc_Wsvhhi8pZSU7xQWEp6e_XO7ch5nWaU_-x9Ja0CN_5V3K6QNl

Java執行試題及答案(非常全面)

這篇文章主要是對多執行緒的問題進行總結的,因此羅列了40個多執行緒的問題。 這些多執行緒的問題,有些來源於各大網站、有些來源於自己的思考。可能有些問題網上有、可能有些問題對應的答案也有、也可能有些各位網友也都看過,但是本文寫作的重心就是所有的問題都會按照自己的理解回答一遍,不會去看網上的

Java執行試題整理(BATJ都愛問)

今天給大家總結一下,面試中出鏡率很高的幾個多執行緒面試題,希望對大家學習和麵試都能有所幫助。備註:文中的程式碼自己實現一遍的話效果會更佳哦! 一、面試中關於 synchronized 關鍵字的 5 連擊 1.1 說一說自己對於 synchronized 關鍵字的瞭解 synchroniz

Java資深架構師詳解大廠多執行試題,細談併發程式設計深造歷程

  多執行緒、執行緒池 多執行緒是實現併發機制的一種有效手段。程序和執行緒一樣,都是實現併發的一個基本單位。執行緒是比程序更小的執行單位,執行緒是程序的基礎之上進行進一步的劃分。所謂多執行緒是指一個程序在執行過程中可以產生多個更小的程式單元,這些更小的單元稱為執行緒,這

java執行試題小結

http://www.importnew.com/12773.html http://www.cnblogs.com/fingerboy/p/5352880.html https://blog.csdn.net/ll666634/article/details/78615505 https://blog

Java執行試題整理

1、什麼是多執行緒 執行緒是作業系統中排程的基本單位 2、執行緒和程序的區別 執行緒是排程的基本單位,而程序是資源分配的基本單位; 3、java如何建立執行緒 繼承java.lang.Thread類 實現Runnable介面的run()方法 注:由於java只能實

15個頂級Java執行試題及回答

原文連結  ,原文作者:Javin Paul ,  譯者:趙峰 Java 執行緒面試問題 在任何Java面試當中多執行緒和併發方面的問題都是必不可少的一部分。如果你想獲得任何股票投資銀行的前臺資訊職位,那麼你應該準備很多關於多執行緒的問題。在投資銀行業務中多執行緒和併發是一個非常受歡迎的話題,