本篇內(nèi)容主要講解“volatile是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“volatile是什么”吧!
10年積累的成都做網(wǎng)站、網(wǎng)站制作經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有新城免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
今天閑來無事跟同事小麥大叔閑聊,
SoWhat:麥叔聽說你偷偷面阿里啦,面的咋樣?
小麥大叔: 一面挺簡單的,主要問了一些基本的數(shù)據(jù)結(jié)構(gòu)跟算法,還問了下 HashMap的十大常見基本問題。我都答案上來了,還問了我JDK7環(huán),幸虧你那個HashMap環(huán)繪制的牛逼,我答的不錯就讓我準備二面了。
SoWhat:二面類?
小麥大叔:二面問了我一些JVM的問題,問我對于JVM內(nèi)存模型的理解,還有GC的常見理解,最終還問了我下類加載機制,我看你之前水過這個 JVM系列,就依葫蘆畫瓢答上來了,讓我準備三面。
SoWhat:麥叔這波可以啊,三面問的啥啊?
小麥大叔:三面問了我一些CAS、Lock、AQS跟 ConcurrentHashMap 的底層實現(xiàn)什么的,還問了我下線程池的七大參數(shù)跟四大拒絕策略,以及使用注意事項。我看你水過 并發(fā)編程系列,也就答上來了。
Sowhat:厲害啊這是要過的節(jié)奏阿!
小麥大叔:過個錘子,三面的這個總監(jiān)最后竟然問了我下我對volatile
的底層原理。你妹的你么水,我就答了一些基本的可見性跟弱原子性,然后我感覺面試官不太滿意啊!
Sowhat:額好吧,那我抓緊再水文寫下個關(guān)于volatile
的使用。
volatile
變量自身具有下列特性相信大家都知道:
可見性。對一個volatile變量的讀,總是能看到(任意線程)對這個volatile變量最后的寫入。
原子性:對任意單個volatile變量的讀/寫具有原子性,但類似于volatile++這種復(fù)合操作不具有原子性。
其中第二點可以理解為把對 volatile 變量的單個讀/寫,看成是使用同一個鎖對這些單個讀/寫操作做了同步,就跟下面的SoWhat
跟SynSoWhat
功能類似哦。
class SoWhat{ volatile int i = 0; // volatile修飾的變量public int getI(){ return i;// 單個volatile變量的讀}public void setI(int j){ this.i = j; // 單個volatile 變量的寫}public void inc(){ i++;//復(fù)合多個volatile 變量}}class SynSoWhat{ int i = 0;public synchronized int getI(){ return i;}public synchronized void setI(int j){ this.i = j;}public void inc(){ // 普通方法調(diào)用int tmp = getI(); // 調(diào)用已同步方法tmp = tmp + 1;//普通寫方法setI(tmp);// 調(diào)用已同步方法}}
volatile寫的內(nèi)存語義如下:
當寫一個
volatile
變量時,JMM會把該線程對應(yīng)的本地中的共享變量值刷新
到主內(nèi)存。
public class VolaSemanteme { int a = 0;volatile boolean flag = false; // 這是重點哦public void init() { a = 1; flag = true; //.......}public void use() { if (flag) { int i = a * a; }//.......}}
線程A調(diào)用init
方法,線程B調(diào)用use
方法。
volatile
讀的內(nèi)存語義如下:
當讀一個volatile變量時,JMM會把該線程對應(yīng)的本地內(nèi)存置為
無效
。線程接下來將從主內(nèi)存中讀取共享變量。
public class VolaSemanteme { int a = 0;volatile boolean flag = false; // 這是重點哦public void init() { a = 1; flag = true; //.......}public void use() { if (flag) { int i = a * a; }//.......}}
流程圖大致是這樣的:
volatile
變量的內(nèi)存可見性是基于內(nèi)存屏障(Memory Barrier)實現(xiàn)。關(guān)于內(nèi)存屏障的具體講解以前寫過不再重復(fù),JMM裝逼于無形這里說過。總結(jié)來說就是JMM內(nèi)部會有指令重排,并且會有af-if-serial
跟happen-before
的理念來保證指令重拍的正確性。內(nèi)存屏障就是基于4個匯編級別的關(guān)鍵字來禁止指令重排的,其中volatile的重拍規(guī)則如下:
第一個為讀操作時,第二個任何操作不可重排序到第一個前面。
第二個為寫操作時,第一個任何操作不可重排序到第二個后面。
第一個為寫操作時,第二個的讀寫操作也不運行重排序。
JMM對volatile的內(nèi)存屏障插入策略
在每個volatile寫操作的前面插入一個StoreStore屏障。在每個volatile寫操作的后面插入一個StoreLoad屏障。
JMM對volatile的內(nèi)存屏障插入策略
在每個volatile讀操作的后面插入一個LoadLoad屏障。在每個volatile讀操作的后面插入一個LoadStore屏障。
其中重點說下volatile
讀后面為什么跟了個LoadLoad
。加入我有如下代碼 AB兩個線程執(zhí)行,B線程的flag獲取下面的讀被提前了。
有volatile變量修飾的共享變量進行寫操作的時候會使用CPU
提供的Lock
前綴指令。在CPU級別的功能如下:
將當前處理器緩存行的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存
這個寫回內(nèi)存的操作會告知在其他CPU你們拿到的變量是無效的下一次使用時候要重新共享內(nèi)存拿。
我們可以通過jitwatch對簡單的代碼進行詳細的反匯編看一下。
package com.sowhat.demo;public class VolaSemanteme { int unvloatileVal = 0;volatile boolean flag = false;public void init() { unvloatileVal = 1;flag = true; // 第九行哦}public void use() { if (flag) { int LocalA = unvloatileVal;if (LocalA == 0) { throw new RuntimeException("error");}}}public static void main(String[] args) { VolaSemanteme volaSemanteme = new VolaSemanteme();volaSemanteme.init();volaSemanteme.use();}}
對普通變量的賦值操作:
對volatile
變量的賦值操作。
可以對比得出,volatile 修飾的變量確實會多一個 lock addl $0x0,(%rsp) 指令。
0x0000000114ce95cb: lock addl $0x0,(%rsp) ;*putfield flag ; - com.sowhat.demo.VolaSemanteme::init@7 (line 9)
到此,相信大家對“volatile是什么”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!
網(wǎng)站題目:volatile是什么
轉(zhuǎn)載源于:http://m.newbst.com/article14/jeijge.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標簽優(yōu)化、營銷型網(wǎng)站建設(shè)、用戶體驗、網(wǎng)站營銷、自適應(yīng)網(wǎng)站、移動網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)