摘要:的缺點(diǎn)頻繁刷新主內(nèi)存中變量,可能會造成性能瓶頸不具備操作的原子性,不適合在對該變量的寫操作依賴于變量本身自己。
作者:畢來生1. 什么是JUC?
微信:878799579
JUC全稱 java.util.concurrent 是在并發(fā)編程中很常用的實(shí)用工具類
2.Volatile關(guān)鍵字1、如果一個變量被volatile關(guān)鍵字修飾,那么這個變量對所有線程都是可見的。
2、如果某條線程修改了被Volatile修飾的這個變量值,修改后的值對于其他線程來時是立即可見的。
3、并不是經(jīng)過Volatile修飾過的變量在多線程下就是安全的
4、多線程間可以使用SynchronousQueue或者Exchanger進(jìn)行數(shù)據(jù)之間傳遞
內(nèi)存可見性(Memory Visibility)是指當(dāng)某個線程正在使用對象狀態(tài) 而另一個線程在同時修改該狀態(tài),需要確保當(dāng)一個線程修改了對象 狀態(tài)后,其他線程能夠看到發(fā)生的狀態(tài)變化。
可見性錯誤是指當(dāng)讀操作與寫操作在不同的線程中執(zhí)行時,我們無法確保執(zhí)行讀操作的線程能適時地看到其他線程寫入的值,有時甚至是根本不可能的事情。
原理同CAS原理相同,不懂的同學(xué)可以自行百度,附上一張CAS演示圖供大家參考
通過線程來修改變量count的值,使用Volatile關(guān)鍵字修飾和不使用Volatile修飾count變量結(jié)果對比。
首先我們來看一下通過內(nèi)部類實(shí)現(xiàn)Runnable,變量使用Volatile關(guān)鍵字修飾演示以及結(jié)果
package org.bilaisheng.juc; /** * @Author: bilaisheng * @Wechat: 878799579 * @Date: 2019/1/1 16:29 * @Todo: 通過內(nèi)部類實(shí)現(xiàn)Runnable,變量使用Volatile關(guān)鍵字修飾演示 * @Version : JDK11 , IDEA2018 */ public class NoVolatileTest{ public static void main(String[] args) { NoVolatileThread noVolatileThread = new NoVolatileThread(); new Thread(noVolatileThread).start(); while (true){ if(noVolatileThread.isFlag()){ System.out.println("flag 此時為true !"); break; } } } } class NoVolatileThread implements Runnable{ private boolean flag = false; @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } flag = true; System.out.println(Thread.currentThread().getName() + " flag = " + flag); } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } }
運(yùn)行結(jié)果如下圖所示:
接下來我們來看一下通過內(nèi)部類實(shí)現(xiàn)Runnable,變量不使用Volatile關(guān)鍵字修飾演示以及結(jié)果
package org.bilaisheng.juc; /** * @Author: bilaisheng * @Wechat: 878799579 * @Date: 2019/1/1 16:53 * @Todo: 通過內(nèi)部類實(shí)現(xiàn)Runnable,變量使用Volatile關(guān)鍵字修飾演示 * @Version : JDK11 , IDEA2018 */ public class VolatileTest{ public static void main(String[] args) { VolatileThread volatileThread = new VolatileThread(); new Thread(volatileThread).start(); while (true){ // if的判斷volatile保證當(dāng)時確實(shí)正確,然后線程a可能處于休眠狀態(tài), // 線程b也判斷不存在,b線程就new了一個。 // 然后a線程wake up,據(jù)需執(zhí)行new volatile獲取最新值。 if(volatileThread.isFlag()){ System.out.println("flag 此時為true !"); break; } } } } class VolatileThread implements Runnable{ private volatile boolean flag = false; @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } flag = true; System.out.println(Thread.currentThread().getName() + " flag = " + flag); } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } }
運(yùn)行結(jié)果如下圖所示:
通過對比我們發(fā)現(xiàn)在通過Volatile修飾和不通過Volatile修飾的變量,輸出結(jié)果竟然會有些偏差。到底是為什么呢?
我們逐步拆解上面代碼執(zhí)行步驟:
1、針對于不使用Volatile關(guān)鍵字修飾變量:
步驟一:默認(rèn)flag = false;
步驟二main線程的緩存區(qū)域沒有刷新 flag的值。所以flag 還是false。故沒有輸出
步驟三:子線程輸出 Thread-0 flag = true
2、針對于使用Volatile關(guān)鍵字修飾變量:
步驟一:默認(rèn)flag = false;
步驟二:主線程看到flag是被Volatile關(guān)鍵字修飾的變量。則獲取最新的flag變量值,此時flag = true。故輸出
步驟三:子線程輸出 Thread-0 flag = true
5. Volatile的優(yōu)點(diǎn)可見性:被Volatile修飾的變量可以馬上刷新主內(nèi)存中的值,保證其他線程在獲取時可以獲取最新值,所有線程看到該變量的值均相同。
輕量級的synchronized,高并發(fā)下保證變量的可見性。
6.Volatile的缺點(diǎn)1、頻繁刷新主內(nèi)存中變量,可能會造成性能瓶頸
2、不具備操作的原子性,不適合在對該變量的寫操作依賴于變量本身自己。例如i++,并不能通過volatile來保證原子性
喜歡就關(guān)注我吧文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/75621.html
摘要:假設(shè)不發(fā)生編譯器重排和指令重排,線程修改了的值,但是修改以后,的值可能還沒有寫回到主存中,那么線程得到就是很自然的事了。同理,線程對于的賦值操作也可能沒有及時刷新到主存中。線程的最后操作與線程發(fā)現(xiàn)線程已經(jīng)結(jié)束同步。 很久沒更新文章了,對隔三差五過來刷更新的讀者說聲抱歉。 關(guān)于 Java 并發(fā)也算是寫了好幾篇文章了,本文將介紹一些比較基礎(chǔ)的內(nèi)容,注意,閱讀本文需要一定的并發(fā)基礎(chǔ)。 本文的...
摘要:因?yàn)楣芾砣藛T是了解手下的人員以及自己負(fù)責(zé)的事情的。處理器優(yōu)化和指令重排上面提到在在和主存之間增加緩存,在多線程場景下會存在緩存一致性問題。有沒有發(fā)現(xiàn),緩存一致性問題其實(shí)就是可見性問題。 網(wǎng)上有很多關(guān)于Java內(nèi)存模型的文章,在《深入理解Java虛擬機(jī)》和《Java并發(fā)編程的藝術(shù)》等書中也都有關(guān)于這個知識點(diǎn)的介紹。但是,很多人讀完之后還是搞不清楚,甚至有的人說自己更懵了。本文,就來整體的...
摘要:因?yàn)楣芾砣藛T是了解手下的人員以及自己負(fù)責(zé)的事情的。處理器優(yōu)化和指令重排上面提到在在和主存之間增加緩存,在多線程場景下會存在緩存一致性問題。有沒有發(fā)現(xiàn),緩存一致性問題其實(shí)就是可見性問題。 網(wǎng)上有很多關(guān)于Java內(nèi)存模型的文章,在《深入理解Java虛擬機(jī)》和《Java并發(fā)編程的藝術(shù)》等書中也都有關(guān)于這個知識點(diǎn)的介紹。但是,很多人讀完之后還是搞不清楚,甚至有的人說自己更懵了。本文,就來整體的...
摘要:當(dāng)某個不應(yīng)該發(fā)布的對象被發(fā)布時,這種情況被稱為逸出。線程安全共享線程安全的對象在其內(nèi)部實(shí)現(xiàn)同步,因此多線程可以通過對象的公有接口來進(jìn)行訪問而不需要進(jìn)一步的同步。 前言 本系列博客是對《Java并發(fā)編程實(shí)戰(zhàn)》的一點(diǎn)總結(jié),本篇主要講解以下幾個內(nèi)容,內(nèi)容會比較枯燥??赡艽蠹铱礃?biāo)題不能能直觀的感受出到底什么意思,這就是專業(yè)術(shù)語,哈哈,解釋下,術(shù)語(terminology)是在特定學(xué)科領(lǐng)域用...
閱讀 3261·2021-11-18 10:02
閱讀 1463·2021-10-12 10:08
閱讀 1264·2021-10-11 10:58
閱讀 1279·2021-10-11 10:57
閱讀 1178·2021-10-08 10:04
閱讀 2133·2021-09-29 09:35
閱讀 783·2021-09-22 15:44
閱讀 1283·2021-09-03 10:30