日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

詳解Java并發編程基礎之volatile

瀏覽:161日期:2022-08-10 18:36:09
目錄一、volatile的定義和實現原理1、Java并發模型采用的方式2、volatile的定義3、volatile的底層實現原理二、volatile的內存語義1、volatile的特性2、volatile寫-讀建立的happens-before關系3、volatile的寫/讀內存語義三、volatile內存語義的實現1、volatile重排序規則2、內存屏障3、內存屏障示例四、volatile與死循環問題五、volatile對于復合操作非原子性問題一、volatile的定義和實現原理1、Java并發模型采用的方式

a)線程通信的機制主要有兩種:共享內存和消息傳遞。

①共享內存:線程之間共享程序的公共狀態,通過寫-讀共享內存中的公共狀態來進行隱式通信;

②消息傳遞:線程之間沒有公共狀態,線程之間 必須通過發送消息來顯式通信。

b)同步:用于控制不同線程之間操作發生相對順序。在

共享內存模型中,同步是顯式的進行的,需要顯示的指定某個方法或者代碼塊在線程執行期間互斥進行。

消息傳遞模型中,由于消息的發送必定在消息的接受之前,所以同步是隱式的進行的。

c)Java并發采用的是共享內存模型,線程之間通信總是隱式的進行,而且這個通信是對程序員透明的。那么我們需要了解的是這個隱式通信的底層工作機制。

2、volatile的定義

Java編程語言中允許線程訪問共享變量,為了確保共享變量能夠被準確和一致性的更新,線程應該確保通過排它鎖單獨獲得這個變量。

3、volatile的底層實現原理

a)在編寫多線程程序中,使用volatile修飾的共享變量在進行寫操作的時候,編譯器生成的匯編代碼中會多出一條lock指令,這條lock指令的作用:

①將當前處理器緩存行中的數據寫回到系統內存 ②這個寫回內存的操作會使得其他CPU里緩存了該內存地址的數據無效

b)參考下面的這張圖理解

詳解Java并發編程基礎之volatile

二、volatile的內存語義1、volatile的特性

a)首先我們來看對單個變量的讀/寫的實現(單個變量的情況可以看做是對同一個鎖對這個變量的讀/寫進行了同步),看下面的例子

package cn.jvm.test;public class TestVolatile1 { volatile long var1 = 0L; public void set(long l) {// TODO Auto-generated method stubvar1 = l; } public void getAndIncrement() {// TODO Auto-generated method stubvar1 ++; //注意++操作 } public long get() {return var1; }}

上面的set和get操作在語義上和使用synchronized修飾后一樣,即下面的這種寫法

package cn.jvm.test;public class TestVolatile1 { volatile long var1 = 0L; public synchronized void set(long l) {// TODO Auto-generated method stubvar1 = l; } public synchronized long get() {return var1; }}

b)但是在上面的用例中,我們使用的var1++操作,整體上沒有原子性,所以如果使用多線程方粉getAndIncrement方法的話,會導致讀出的數據和主存中不一致的情況。

c)volatile變量的特性

①可見性:對一個volatile變量的讀操作,總是能夠看到對這個volatile變量最后的寫入

②原子性:對任意單個volatile變量的讀寫具有原子性,但是對于volatile變量的復合型操作并不具備原子性

2、volatile寫-讀建立的happens-before關系

a)看下面的代碼實例

package cn.jvm.test;public class TestVolatile2 { int a = 0; volatile boolean flag = false; public void writer() {a = 1;flag = true; } public void reader() {if(flag) { int i =a; //...其他操作} }}

b)在上面的程序中,假設線程A執行write方法,線程B執行reader方法,根據happens-before規則有下面的關系:

程序次序規則:①happens-before②; ③happens-before④

volatile規則:②happens-before③

傳遞性規則:①happens-before④

所以可以得到下面的這個狀態圖

詳解Java并發編程基礎之volatile

3、volatile的寫/讀內存語義

a)下面是volatile的寫/讀內存語義

①當寫一個volatile變量時候,JMM會將線程對應的本地內存中的共享變量值刷新到主內存中

②當讀一個volatile變量的時候,JMM會將線程對應的本地內存置為無效,然后從主內存中讀取共享變量

b)還是參照上面的程序示例,參考視圖的模型來進行說明

①寫內存語義的示意圖:假設線程A執行writer方法,線程B執行reader方法,初始狀況下線程A和B中的變量都是初始狀態

詳解Java并發編程基礎之volatile

②寫內存語義的示意圖:

詳解Java并發編程基礎之volatile

三、volatile內存語義的實現

我們上面說到的基本上從宏觀上而言都是說明了volatile保證內存可見性問題,volatile的另一個語義就是禁止指令重排序的優化。下面說一下volatile禁止指令重排序的實現細節

1、volatile重排序規則

①當第二個操作是volatile寫的時候,不管第一個操作是什么,都不能進行指令重排序。這個規則確保volatile寫之前的操作都不會被重排序到volatile寫之后。也是為了保證volatile寫對其他線程可見

②當第一個操作為volatile讀的時候,不管第二個操作是什么,都不能進行重排序。確保volatile讀之后的操作不會被重排序到volatile讀之前

③當第一個操作是volatile寫,第二個操作是volatile讀的時候,不能進行重排序

如下所示,上面的是下表中的總結。

詳解Java并發編程基礎之volatile

2、內存屏障

編譯器在生成字節碼的時候,會在指令序列中插入內存屏障來禁止對特定類型的處理器重排序。下面是集中策略,后面會說明這幾種情況

①在每個volatile寫操作之前插入StoreStore屏障

②在每個volatile寫操作之后插入StoreLoad屏障

③在每個volatile讀操作之后插入LoadLoad屏障

④在每個volatile讀操作之后插入LoadStore屏障

3、內存屏障示例

a)volatile寫插入內存屏障之后的指令序列圖

詳解Java并發編程基礎之volatile

b)volatile讀插入內存屏障后的指令序列圖

詳解Java并發編程基礎之volatile

四、volatile與死循環問題

1、先看下面的示例代碼,觀察運行結果,當共享變量isRunning沒有被聲明為volatile的時候,main線程會在2秒之后將共享變量isRunning置為false并且輸出修改信息,這樣新建的線程應該結束運行,但是實際上并沒有,控制臺中會一直保持運行的狀態,并且不會打印線程結束執行;如下所示

詳解Java并發編程基礎之volatile

package cn.jvm.test;class ThreadDemo extends Thread { private boolean isRunning = true; @Override public void run() {System.out.println(Thread.currentThread().getName() + ' 開始執行');while(isRunning) {}System.out.println(Thread.currentThread().getName() + ' 結束執行'); } public boolean isRunning() {return isRunning; } public void SetIsRunning(boolean isRunning) {this.isRunning = isRunning; }}public class TestVolatile4 { public static void main(String[] args) {ThreadDemo td = new ThreadDemo();td.start();try { Thread.sleep(2000); td.SetIsRunning(false); System.out.println(Thread.currentThread().getName() + ' 線程將共享變量值修改為false');} catch (Exception e) { // TODO: handle exception e.printStackTrace();} }}

2、分析出現上面結果的原因

在啟動線程ThreadDemo之后,變量isRunning被存在公共堆棧以及線程的私有堆棧中,后//續中線程一直在私有堆棧中取出isRunning的值,雖然main線程執行SetIsRunning方法修改了isRunning的值,但是這個值并沒有被Thread-//0線程所知,就像上面說的Thread-0取得值一直都是私有堆棧中的,所以不會知道isRunning被修改,也就不會退出循環

3、按照上面的原因分析一下執行的時候的工作內存和主內存的情況,按照下面的分析我們很容易得出結論

上面的問題就是因為工作內存(私有堆棧)和主內存(公共堆棧)中的值不同步。而按照我們上面說到的volatile使得單個變量保證線程可見性,就可以對程序修改保證共享變量在main線程中的修改對Thread-0線程可見(結合volatile的實現原理)

詳解Java并發編程基礎之volatile

4、修改之后的結果

詳解Java并發編程基礎之volatile

package cn.jvm.test;class ThreadDemo extends Thread { private volatile boolean isRunning = true; @Override public void run() {System.out.println(Thread.currentThread().getName() + ' 開始執行');while(isRunning) { }System.out.println(Thread.currentThread().getName() + ' 結束執行'); } public boolean isRunning() {return isRunning; } public void SetIsRunning(boolean isRunning) {this.isRunning = isRunning; }}public class TestVolatile4 { public static void main(String[] args) {ThreadDemo td = new ThreadDemo();td.start();try { Thread.sleep(2000); td.SetIsRunning(false); System.out.println(Thread.currentThread().getName() + ' 線程將共享變量值修改為false');} catch (Exception e) { // TODO: handle exception e.printStackTrace();} }}

詳解Java并發編程基礎之volatile

五、volatile對于復合操作非原子性問題

1、volatile能保證對單個變量在多線程之間的可見性問題,但是對于單個變量的復合操作不能保證原子性,如下代碼示例,運行結果為

詳解Java并發編程基礎之volatile

當然這個結果是隨機的,但是不能保證運行結果是100000

在沒有使用同步操作之前,雖然count變量是volatile的,但是由于count++操作是個復合操作

①從內存中取出count的值

②計算count的值

③將count的值寫到內存中

這個復合操作由于volatile不能保證原子性,所以就會出現錯誤

package cn.jvm.test;import java.util.ArrayList;import java.util.List;public class TestVolatile5 { volatile int count = 0; /*synchronized*/ void m(){for(int i = 0; i < 10000; i++){ count++;} } public static void main(String[] args) {final TestVolatile5 t = new TestVolatile5();List<Thread> threads = new ArrayList<>();for(int i = 0; i < 10; i++){ threads.add(new Thread(new Runnable() {@Overridepublic void run() { t.m();} }));}for(Thread thread : threads){ thread.start();}for(Thread thread : threads){ try {thread.join(); } catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace(); }}System.out.println(t.count); }}

2、下面按照JVM的內存工作來分析一下,即當前一個線程在計算count變量的時候,另一個線程已經修改了count變量的值,這樣就必然會出現錯誤。所以對于這種復合操作就需要使用原子類或者使用synchronized來保證原子性(保證同步)

詳解Java并發編程基礎之volatile

3、修改后的synchronized和使用原子類如下所示

package cn.jvm.test; import java.util.ArrayList; import java.util.List; public class TestVolatile5 { int count = 0; synchronized void m(){ for(int i = 0; i < 10000; i++){ count++; } } public static void main(String[] args) { final TestVolatile5 t = new TestVolatile5(); List<Thread> threads = new ArrayList<>(); for(int i = 0; i < 10; i++){ threads.add(new Thread(new Runnable() { @Override public void run() { t.m(); } })); } for(Thread thread : threads){ thread.start(); } for(Thread thread : threads){ try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(t.count); } }

package cn.jvm.test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class TestVolatile5 { AtomicInteger count = new AtomicInteger(0); void m(){ for(int i = 0; i < 10000; i++){ count.getAndIncrement(); } } public static void main(String[] args) { final TestVolatile5 t = new TestVolatile5(); List<Thread> threads = new ArrayList<>(); for(int i = 0; i < 10; i++){ threads.add(new Thread(new Runnable() { @Override public void run() { t.m(); } })); } for(Thread thread : threads){ thread.start(); } for(Thread thread : threads){ try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(t.count); } }

以上就是詳解Java并發編程基礎之volatile的詳細內容,更多關于Java 并發編程 volatile的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产精品超碰| 在线人成日本视频| 日本少妇一区| 精品亚洲a∨| 中文字幕av一区二区三区人| 99在线精品免费视频九九视 | 国产精品调教视频| 国产精品mm| 国产精品国产三级国产在线观看| 青青草91视频| 国产极品久久久久久久久波多结野| 国产精品一区二区免费福利视频| 国产精品最新自拍| 精品视频97| 欧洲一级精品| 美女91精品| 日韩欧美中文在线观看| 国产视频一区二区在线播放| 国产剧情在线观看一区| 国产精品v日韩精品v欧美精品网站| 国产日韩三级| 欧美日韩一区二区高清| 国产日产精品_国产精品毛片 | 国产一区二区三区日韩精品 | 久久成人福利| 国产精品白丝一区二区三区| 国产欧美久久一区二区三区| 欧美日一区二区三区在线观看国产免 | 理论片午夜视频在线观看| 国产精品一区二区免费福利视频| 久久国产麻豆精品| 色爱av综合网| 伊伊综合在线| 亚洲精品在线影院| 日韩欧美一区二区三区在线观看 | 精品黄色一级片| 国产一区国产二区国产三区 | 91成人在线| 国产欧美一级| 国产精品a级| 亚洲精选久久| 婷婷视频一区二区三区| 久久国产视频网| 婷婷久久免费视频| 精品一区视频| 亚洲综合电影| 国产综合精品| 中文一区一区三区免费在线观 | 欧美大黑bbbbbbbbb在线| 亚洲精品2区| 中文字幕一区二区精品区| 亚洲女人av| 日本一区二区中文字幕| 国产欧美日韩一区二区三区在线| 欧美激情福利| 日韩国产欧美| 一区在线免费观看| 日韩欧美中文字幕一区二区三区| 青青国产精品| 精品在线网站观看| 精品欧美激情在线观看| 亚洲免费观看高清完整版在线观| 国产毛片精品| 亚洲www啪成人一区二区| 亚洲激情偷拍| 欧美亚洲二区| 欧美激情在线精品一区二区三区| 在线一区av| 欧美日韩国产高清| 免费在线观看视频一区| 欧美精品国产白浆久久久久| 精品视频国产| 香蕉人人精品| 午夜性色一区二区三区免费视频| 美女精品视频在线| 婷婷综合激情| 国产精品最新| 国产伊人精品| 国产日韩免费| 不卡一区综合视频| 国产精品porn| 999国产精品999久久久久久| 蜜桃久久av| 精品欧美日韩精品| 国产精品腿扒开做爽爽爽挤奶网站| 日韩不卡一区二区三区| 国产成人精品亚洲日本在线观看| 国产一区成人| 美日韩一区二区三区| 日韩午夜av在线| 久久这里只有| 在线观看亚洲精品福利片| 久久麻豆视频| 国产视频一区在线观看一区免费| 国产精品麻豆成人av电影艾秋| 亚洲大片在线| 国产精品一区二区三区av麻| 亚洲一级二级| 麻豆精品少妇| 亚洲精品第一| 久久精品国产亚洲夜色av网站 | 黑丝一区二区三区| 国产精品男女| 蜜桃久久av| 91精品亚洲| 美女免费视频一区| 亚洲综合色婷婷在线观看| 日韩一区欧美| 久久福利在线| 天堂va欧美ⅴa亚洲va一国产| 欧美日本二区| 国产亚洲在线观看| 欧美久久一区二区三区| 玖玖精品视频| 久久久人人人| 久久中文在线| 日本强好片久久久久久aaa| 九九久久婷婷| av中文资源在线资源免费观看| 日本成人中文字幕| 午夜在线视频观看日韩17c| 日本韩国欧美超级黄在线观看| 国产一精品一av一免费爽爽| 麻豆成人在线| 午夜精品免费| 亚洲黄色免费看| 国产精品伦一区二区| 亚洲综合色婷婷在线观看| 亚洲女同中文字幕| 视频二区不卡| 9999国产精品| 久久精品一区| 欧美日韩午夜电影网| 免播放器亚洲一区| 黄色精品网站| 亚洲免费黄色| 午夜国产一区二区| 亚洲二区精品| 91精品蜜臀一区二区三区在线| 欧美天堂视频| 成人午夜在线| 精品国产乱码久久久久久1区2匹| 欧美一区自拍| 欧美精品中文| 国产日韩一区二区三区在线播放| 亚洲精品观看| 国产视频一区免费看| 中文久久精品| 久久都是精品| 9国产精品视频| 亚洲精品在线观看91| 国户精品久久久久久久久久久不卡| 欧美黄色网页| 99久久九九| 亚洲四虎影院| 丝袜美腿诱惑一区二区三区| 88xx成人免费观看视频库| 日韩专区精品| 久久婷婷激情| 免费成人网www| 欧美亚洲精品在线| 午夜日韩在线| 免费国产亚洲视频| 日韩高清成人在线| 国产精品一区三区在线观看| 国产精品1区在线| 精品国产一区二区三区av片| 精品日韩一区| 国产一区二区亚洲| 久久精品国产99国产| 久久国产欧美日韩精品| 欧美欧美黄在线二区| 深夜日韩欧美| 精品视频高潮| 久久青草久久| 国产一区91| 日韩1区2区日韩1区2区| 国产精品白浆| 国产精品久久观看| 激情五月综合网| 亚洲人成亚洲精品| 国产亚洲观看| 日本一二区不卡| 欧美亚洲激情| 综合在线一区| 国产激情久久| 成人在线免费观看网站| 蜜桃精品在线| 亚洲欧美高清| 国产精品日本一区二区不卡视频| 国产精品久久久一区二区| 麻豆久久一区二区| 日韩不卡视频在线观看| 日韩欧美1区| 亚洲精品在线a| 免费日韩成人| 999久久久精品国产| 蜜臀久久99精品久久久画质超高清| 欧美亚洲综合视频| 日本精品影院|