色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

Java多線程volatile原理及用法解析

瀏覽:42日期:2022-08-28 10:36:39

首先volatile有兩大功能:

保證線程可見(jiàn)性

禁止指令重排序

1、保證線程可見(jiàn)性

首先我們來(lái)看這樣一個(gè)程序,其中不加volatile關(guān)鍵字運(yùn)行的結(jié)果截然不同,加上volatile程序能夠正常結(jié)束,不加則程序進(jìn)入死循環(huán);

package com.designmodal.design.juc01;import java.util.concurrent.TimeUnit;/** * @author D-L * @Classname T001_volatile * @Version 1.0 * @Description volatile 保證線程的可見(jiàn)性 * @Date 2020/7/19 17:30 */public class T001_volatile { //定義一個(gè)變量running volatile boolean running = true; public void m(){ while(running){ //TODO 不做任何的處理 System.out.println('while is running When can I stop -------------'); } System.out.println('method is end ---------------'); } public static void main(String[] args) { T001_volatile t001_volatile = new T001_volatile(); new Thread(t001_volatile::m , 'Thread t1').start(); //停一秒 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } //修改running的值 t001_volatile.running = false; }}

通過(guò)上面的小程序說(shuō)明volatile是具有保證線程之間的可見(jiàn)性的功能的,具體是如何實(shí)現(xiàn)的呢?下面給大家解釋一下:

之前在上一篇講synchronized時(shí)提到了 堆內(nèi)存是線程共享的,而線程在工作時(shí)有自己的工作內(nèi)存,對(duì)于共享變量running來(lái)說(shuō),線程1和線程2在運(yùn)行的時(shí)候先把running變量copy到自己工作內(nèi)存,對(duì)這個(gè)變量的改變都是在自己的工作內(nèi)存中,并不會(huì)直接的反映到其他線程,如果加了volatile,running變量改變其他線程很快就會(huì)知道,這就是線程的可見(jiàn)性;

Java多線程volatile原理及用法解析

這里用到的是:MESI(CPU緩存一致性協(xié)議) MESI的主要思想:當(dāng)CPU寫數(shù)據(jù)時(shí),如果該變量是共享數(shù)據(jù),給其他CPU發(fā)送信號(hào),使得其他的CPU中的該變量的緩存行無(wú)效;歸根結(jié)底這里需要借助硬件來(lái)幫助我們。

Java多線程volatile原理及用法解析

volatile保證線程可見(jiàn)性但是不能代替synchronized:

package com.designmodal.design.juc01;import java.util.ArrayList;import java.util.List;/** * @author D-L * @Classname VolatileAndSynchronized * @Version 1.0 * @Description synchronized can not be replaced by volatile *volatile 不能代替synchronized *只能保證可見(jiàn)性 不能保證原子性 *count++ 不是原子性操作 * @Date 2020/xx/xx 23:25 */public class VolatileAndSynchronized { volatile int count = 0; public synchronized void m(){ for (int i = 0; i < 1000; i++) { //非原子性操作 匯編指令至少有三條 count++; } } public static void main(String[] args) { VolatileAndSynchronized v = new VolatileAndSynchronized(); List<Thread> threads = new ArrayList<>(); for (int i = 0; i < 10; i++) { threads.add(new Thread(v::m , 'Thread'+ i)); } threads.forEach(o ->o.start()); threads.forEach(o ->{ try {o.join(); } catch (InterruptedException e) {e.printStackTrace(); } }); System.out.println(v.count); }}

2、禁止指令重排序

指令重排序也是和CPU有關(guān)系,加了volatile之后,每次寫都會(huì)背線程看到。CPU原來(lái)執(zhí)行指令時(shí),是按照一步一步順序來(lái)執(zhí)行的,但是CPU為了提高效率它會(huì)把指令并發(fā)來(lái)執(zhí)行,第一個(gè)指令執(zhí)行到一半的時(shí)候第二條指令就可能已經(jīng)開(kāi)始執(zhí)行了,這叫流水線式的執(zhí)行;為了充分的利用CPU,就要求編譯器把編譯完的源碼指令,可能會(huì)進(jìn)行一個(gè)指令重新排序;這種架構(gòu)通過(guò)實(shí)際驗(yàn)證,很大效率上提高了CPU的使用效率。

下面從一個(gè)面試題來(lái)討論一下指令重排序:

面試官:你聽(tīng)過(guò)單例模式嗎?

你:當(dāng)然聽(tīng)過(guò),不然沒(méi)法聊了。

package com.designmodal.design.juc01;import java.util.concurrent.TimeUnit;/** * @author D-L * @Classname T002_volatile * @Version 1.0 * @Description volatile 指令重排序 * @Date 2020/7/20 00:48 */public class T002_volatile { //創(chuàng)建私有的 T002_volatile 有人會(huì)問(wèn)這里的volatile要不要使用,這里的答案是肯定的 private static /**volatile*/ volatile T002_volatile INSTANCE; public T002_volatile() {} public T002_volatile getInstance(){ //模擬業(yè)務(wù)代碼 這里為了synchronized更加細(xì)粒度,所以使用了雙重檢查 if(INSTANCE == null){ synchronized (this){ //雙重檢查 if(INSTANCE == null){ //避免線程之間的干擾 在這里睡一秒 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } //創(chuàng)建實(shí)例對(duì)象 INSTANCE = new T002_volatile(); } } } return INSTANCE; } /** * 創(chuàng)建100個(gè)線程 調(diào)用getInstance() 打印hashcode值 * @param args */ public static void main(String[] args) { T002_volatile t001_volatile = new T002_volatile(); for (int i = 0; i < 100; i++) { new Thread(() ->{T002_volatile instance = t001_volatile.getInstance();System.out.println(instance.hashCode()); }).start(); } }}

在上述的代碼中:INSTANCE = new T002_volatile(); 經(jīng)過(guò)編譯后的指令是分三步的

1、給指令申請(qǐng)內(nèi)存

2、給成員變量初始化

3、把這塊對(duì)象的內(nèi)容賦給INSTANCE

在第二步這里既然已經(jīng)有默認(rèn)值了,第二個(gè)線程來(lái)檢查,發(fā)現(xiàn)已經(jīng)有值了根本就不會(huì)進(jìn)入鎖住的那份代碼;加了volatile就不會(huì)出現(xiàn)指令重排序了,所以在這個(gè)時(shí)候一定要保證初始化完成之后才會(huì)賦值給這個(gè)變量,這就是volatile存在的意義。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持好吧啦網(wǎng)。

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 欧美视频一区在线观看 | 国产精品亚洲一区二区在线观看 | 久久精品国产精品青草 | 草草在线观看视频 | 九九精品免费观看在线 | 在线精品免费观看综合 | 可以免费看黄的网址 | 亚洲日本va午夜中文字幕 | 国产在线播放不卡 | 美女黄频免费观看 | 91视频国产一区 | 三级国产三级在线 | 欧美日韩精品在线视频 | 美女黄色免费在线观看 | 日本久久伊人 | 亚洲精品国产精品精 | 中文一区在线 | 精品视频在线看 | 草草视频免费在线观看 | 欧美日韩a∨毛片一区 | 国产日产欧产精品精品推荐小说 | 亚洲精品成人在线 | 日韩欧美在线视频观看 | 97高清国语自产拍中国大陆 | a毛片在线还看免费网站 | 一级毛片在线免费观看 | 国产亚洲小视频 | 久久久久久青草大香综合精品 | 国产精品青草久久久久福利99 | 免费一区区三区四区 | 农村寡妇一级毛片免费播放 | 亚洲一区二区精品 | 韩国美女豪爽一级毛片 | 青青草国产免费久久久91 | 亚洲九九夜夜 | 天堂一区二区三区在线观看 | 亚洲综合亚洲 | 成人97| 视频亚洲一区 | 很黄很暴力深夜爽爽无遮挡 | 毛片99|