Java 面試官最喜歡問的關鍵字 volatile

筆者去年面試過幾家公司,基本上每家公司都會問到volatile,甚至有的公司每輪面試的時候都會問到。面試官這麼喜歡問volatile就是由於這個關鍵字涉及到的知識點較多好比Java內存模型、內存屏障、happen-befor等知識,能夠繼續挖掘到系統指令、超線程等知識。面試

Java內存模型(JMM)sql

volatile是Java虛擬機提供的最輕量的同步機制,但很難被正確的理解與使用,經過學習Java內存模型對volatile專門定義的一些特殊訪問規則,或許會對理解volatile有必定幫助。緩存

Java內存模型定義了線程和內存之間關係:線程之間的共享變量存儲在主內存中,每一個線程都有一個私有的本地內存,本地內存中存儲了該線程以讀 / 寫共享變量的副本。本地內存是 JMM 的一個抽象概念,並不真實存在;它涵蓋內存、緩存、寄存器以及其餘的硬件和編譯器優化。Java的內存模型抽象以下:架構

volatile的語義併發

volatile主要提供了兩種語義:app

1,可見性:分佈式

可見性是指一個線程寫入的值,其餘線程可以當即讀取。在由Java內存模型可知道,每一個線程都是有本地內存。因此線程A寫入在正常狀況下,線程B不能當即讀取。可是在volatile變量,能夠保證線程A不寫入本地內存直接寫入主內存,線程B直接從主內存中讀取,不從本地內存中讀取。函數

2,禁止指令重排序:高併發

重排序是指編譯器和處理器爲了優化程序性能而對指令進行重排序的一種優化手段。性能

Java程序的幾種重排序

編譯器優化重排序:編譯器在不改變單線程程序語義的前提下,能夠從新安排語句的執行順序。 指令級並行的重排序:若是不存在數據依賴性,處理器能夠改變語句對應機器指令的執行順序。 內存系統的重排序:處理器使用緩存和讀寫緩衝區,這使得加載和存儲操做看上去多是在亂序執行 volatile的技術基石--內存屏障

內存屏障是cpu指令,該指令保證特定操做的順序性和某些內存的可見性。插入一條內存屏障指令以後會告訴編譯器和CPU:無論什麼指令都不能和這條指令重排序。 內存屏障所作的另一件事情就是強制刷出各類CPU cache, 如一個Write-Barrier(寫入屏障)將刷出全部在Barrier以前寫入cache的數據,所以,任何CPU上的線程都能讀取到這些數據的最新版本。

對於Java程序而言, 若是把加入volatile關鍵字的代碼和未加入volatile關鍵字的代碼都生成彙編代碼,會發現加入volatile關鍵字的代碼會多出一個lock前綴指令。

volatile的典型用例

狀態標誌,代碼示例以下:

線程1執行run()的過程當中,可能有另外的線程2調用了shutdown,因此stop變量必須是volatile(利用的volatile的可見性)。

還有一種常見的用法在雙重檢驗的單例實現上,代碼以下:

instance = new Singleton()這句,這並不是是一個原子操做,事實上在 JVM 中這句話大概作了下面 3 件事情:

給 instance 分配內存 調用 Singleton 的構造函數來初始化成員變量 將instance對象指向分配的內存空間(執行完這步 instance 就爲非 null 了) 若是 instance變量沒有加volatile, 由於指令重排序的存在,就可能致使執行步驟是1-2-3,也多是1-3-2。一旦是1-3-2,就可能會致使訪問未初始化的內存。可是加上 volatile關鍵字以後,必定保證是按照1-2-3步驟執行的(利用的 volatile的禁止重排序 )。

歡迎工做一到五年的Java工程師朋友們加入Java架構師:697558955

羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!

相關文章
相關標籤/搜索