最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java多線程之線程同步

 更新時(shí)間:2021年05月06日 14:18:19   作者:IT爛筆頭  
這篇文章主要介紹了Java多線程之線程同步,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下

volatile

先看個(gè)例子

class Test {
		// 定義一個(gè)全局變量
    private boolean isRun = true;
 
	  // 從主線程調(diào)用發(fā)起
    public void process() {
        test();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        stop();
    }
		// 啟動(dòng)一個(gè)子線程循環(huán)讀取isRun
    private void test() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (isRun) {
									// 疑問,如果我這里有一些打印的語句或者線程睡眠的語句,子線程在
									// 主線程將isRun改為false的時(shí)候,就會(huì)跳出死循環(huán),反之,如果循環(huán)體
									// 內(nèi)是空的,就算在主線程改了isRun的值,也無法及時(shí)跳出循環(huán),why?
									// 當(dāng)然,如果將isRun變量使用volatile修飾就沒有此問題
                }
            }
        }).start();
    }
 
    private void stop() {
        isRun = false;
    }
}

有一點(diǎn)是一定的,就是子線程訪問isRun的時(shí)候會(huì)拷貝一份放到自己的線程(工作內(nèi)存)里,這樣在讀寫的時(shí)候可能就不會(huì)和外面isRun的值實(shí)時(shí)是匹配上的。所以就會(huì)出現(xiàn)意想不到的問題。

所以我們使用volatile修飾,這樣當(dāng)有多線程同時(shí)訪問一個(gè)變量時(shí),都會(huì)自動(dòng)同步一下。顯然這樣會(huì)帶來一定的性能損失,但是如果確實(shí)需要還是要這么做的。

但是,有一個(gè)問題來了,使用volatile一定能就可解決多線程同步的問題了嗎?那我們看下面這個(gè)例子:

class TestSynchronize {
 
		// 使用volatile修飾的變量
    private volatile int x = 0;
 
    private void add() {
        x++;
    }
 
    public void test() {
				// 啟動(dòng)第一個(gè)線程,進(jìn)行100萬次自加
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0; i< 1_000_000; i++) {
                    add();
                }
                System.out.println("第一個(gè)線程x=" + x);
            }
        }).start();
				// 啟動(dòng)第二個(gè)線程,進(jìn)行100萬次自加
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0; i< 1_000_000; i++) {
                    add();
                }
                System.out.println("第二個(gè)線程x=" + x);
            }
        }).start();
    }
}

我們希望的結(jié)果是,最后一個(gè)執(zhí)行完的線程應(yīng)該是在2_000_000,但是只要你實(shí)際測(cè)下就發(fā)現(xiàn)并不是這樣,因?yàn)関olatile只能保證可見性,但是只要涉及多線程我們一定還聽說過原子性這個(gè)概念。什么是可見性:

可見性:對(duì)于多個(gè)線程都在訪問的變量,當(dāng)有個(gè)線程在修改的時(shí)候,它會(huì)保證會(huì)將修改的值更新到內(nèi)存中,而不是只在工作線程中修改,這樣當(dāng)別的線程訪問的時(shí)候也會(huì)去內(nèi)存中取最新的值,這樣就能保證訪問到的值是最新的。

那什么又是原子性呢:

原子性:就是一個(gè)操作或者多個(gè)操作要么都執(zhí)行,要么都不執(zhí)行,不會(huì)存在執(zhí)行一半會(huì)被打斷。

在Java中,對(duì)基本數(shù)據(jù)類型變量的讀取和賦值操作是原子性的。但是上述代碼中的x++;顯然不是原子操作,可以拆解為:

int temp = x + 1;
x = temp;

那么這就為多線程操作帶來不確定性,

1、開始x初始值為0,

2、當(dāng)線程A調(diào)用add()函數(shù)時(shí),執(zhí)行到temp=x+1;這一行時(shí)被中斷了,

3、此時(shí)切換到線程B的add()函數(shù),線程B完整執(zhí)行完兩行代碼后,x = 1了,

4、這個(gè)時(shí)候線程B又完整的執(zhí)行了一遍add方法,那么x=2了,

5、此時(shí)發(fā)生了線程切換,切換到A執(zhí)行,A接著上次的執(zhí)行的語句,temp = 1了,接下來執(zhí)行x = temp;語句將1賦值給了x。

可是本來x都被B線程加到2了,這下又回去了,經(jīng)歷A和B線程一共三次add()操作,結(jié)果x的值只是1。

這就解釋了上面那段代碼中,兩個(gè)線程分別加了100萬次后,結(jié)果最后一個(gè)執(zhí)行完的線程打印的卻并不是200萬。原因就是add()里面的操作并不是原子性的,而volatile只能保證可見性,不能保證原子性

當(dāng)然,僅針對(duì)上面的按理我們可以將int x = 0;換一種類型聲明,比如使用AtomicInteger x = new AtomicInteger(0);然后將x++改成x.incrementAndGet();這樣也能保證原子性,確保多線程操作后數(shù)據(jù)是符合期望的。

除了針對(duì)基本數(shù)據(jù)類型的,還有對(duì)引用操作原子化的,AtomicReference<V>

synchronized

當(dāng)synchronized修飾一個(gè)方法時(shí),那么同一時(shí)間只有一個(gè)線程可以訪問此方法,如果有多個(gè)方法都被synchronized修飾的話,當(dāng)一個(gè)線程訪問了其中一個(gè)方法,別的線程就無法訪問其他被synchronized修飾的方法。

相當(dāng)于有一個(gè)監(jiān)視器,當(dāng)一個(gè)線程訪問某個(gè)方法,其他線程想訪問別的方法時(shí),需要和同一個(gè)監(jiān)視器做確認(rèn),這么做看起來不太合理,其實(shí)也是合理的,比如有兩方法都可能對(duì)同一個(gè)變量做操作,兩個(gè)線程能同時(shí)訪問兩個(gè)方法,這樣數(shù)據(jù)還是會(huì)發(fā)生錯(cuò)亂。

當(dāng)然,我們就有兩個(gè)方法支持同步訪問的場(chǎng)景的,只要我們自己確認(rèn)兩個(gè)方法不會(huì)存在數(shù)據(jù)上的錯(cuò)亂,我們可以為每個(gè)方法指定自己的監(jiān)視器,在默認(rèn)情況下是當(dāng)前類的對(duì)象(this)。

我們分別為setName();和其他兩個(gè)方法指定了不同的monitor(監(jiān)視器),這樣當(dāng)線程A訪問上面兩個(gè)方法的時(shí)候,線程B想訪問方法setName也是不受影響的:

接下來我們看我們經(jīng)常寫的另一個(gè)例子,單例模式:

class TestInstance {
    private TestInstance(){}
    
    private static TestInstance sInstance;
    
    public static TestInstance newInstance() {
				**// ② 這里判空的目的?**
        if (sInstance == null) {
						**// ① 為什么鎖加在這里?**
            synchronized (TestInstance.class) {
								**// ③ 這里判空的目的?**
                if (sInstance == null) {
                    sInstance = new TestInstance();
                }
            }
        }
        return sInstance;
    }
}

我們來依次搞清楚上面的三個(gè)問題,

①鎖為什么加在里面而不是在方法上加鎖,因?yàn)榧渔i后會(huì)帶來性能上的損失的,單例對(duì)象只會(huì)創(chuàng)建一次,沒必要在實(shí)例已經(jīng)有的時(shí)候獲取單例時(shí)還加鎖,對(duì)性能是浪費(fèi)。

②第一個(gè)判空的目的就是在已經(jīng)創(chuàng)建過實(shí)例之后的獲取操作,不用再經(jīng)過synchronized判斷,這樣更快。

③最后一個(gè)判空就是防止多個(gè)線程都會(huì)調(diào)到創(chuàng)建實(shí)例的操作。

到此這篇關(guān)于Java多線程之線程同步的文章就介紹到這了,更多相關(guān)Java線程同步內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java單向鏈表的實(shí)現(xiàn)實(shí)例

    java單向鏈表的實(shí)現(xiàn)實(shí)例

    java單向鏈表的實(shí)現(xiàn)實(shí)例。需要的朋友可以過來參考下,希望對(duì)大家有所幫助
    2013-10-10
  • Mybatis入門指南之實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)增刪改查

    Mybatis入門指南之實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)增刪改查

    數(shù)據(jù)持久層主要負(fù)責(zé)數(shù)據(jù)的增、刪、改、查等功能,MyBatis 則是一款優(yōu)秀的持久層框架,下面這篇文章主要給大家介紹了關(guān)于Mybatis入門指南之實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)增刪改查的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • Springboot實(shí)例講解實(shí)現(xiàn)寵物醫(yī)院管理系統(tǒng)流程

    Springboot實(shí)例講解實(shí)現(xiàn)寵物醫(yī)院管理系統(tǒng)流程

    讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Springboot實(shí)現(xiàn)寵物醫(yī)院綜合管理系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平
    2022-06-06
  • Go?Java算法之為運(yùn)算表達(dá)式設(shè)計(jì)優(yōu)先級(jí)實(shí)例

    Go?Java算法之為運(yùn)算表達(dá)式設(shè)計(jì)優(yōu)先級(jí)實(shí)例

    這篇文章主要為大家介紹了Go?Java算法之為運(yùn)算表達(dá)式設(shè)計(jì)優(yōu)先級(jí)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Java前后端的JSON傳輸方式(前后端JSON格式轉(zhuǎn)換)

    Java前后端的JSON傳輸方式(前后端JSON格式轉(zhuǎn)換)

    這篇文章主要介紹了Java前后端的JSON傳輸方式(前后端JSON格式轉(zhuǎn)換),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • java中Swing會(huì)奔跑的線程俠

    java中Swing會(huì)奔跑的線程俠

    本文通過代碼示例給大家詳細(xì)講解了java中Swing會(huì)奔跑的線程俠這個(gè)經(jīng)典的示例,有興趣的朋友學(xué)習(xí)下。
    2018-03-03
  • Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐

    Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐

    本文主要介紹了Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Java引用隊(duì)列和虛引用實(shí)例分析

    Java引用隊(duì)列和虛引用實(shí)例分析

    這篇文章主要介紹了Java引用隊(duì)列和虛引用,結(jié)合實(shí)例形式分析了java引用隊(duì)列和虛引用相關(guān)概念、原理與使用方法,需要的朋友可以參考下
    2019-08-08
  • Java編寫實(shí)現(xiàn)多人聊天室

    Java編寫實(shí)現(xiàn)多人聊天室

    這篇文章主要為大家詳細(xì)介紹了Java編寫實(shí)現(xiàn)多人聊天室,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Shiro的運(yùn)行大致流程詳解

    Shiro的運(yùn)行大致流程詳解

    這篇文章主要介紹了Shiro的運(yùn)行大致流程詳解,Shiro和SpringSecurity都是Java領(lǐng)域中常用的安全框架,它們都提供了身份認(rèn)證和授權(quán)功能,可以幫助開發(fā)者快速構(gòu)建安全的應(yīng)用程序,需要的朋友可以參考下
    2023-07-07

最新評(píng)論

济源市| 山西省| 额敏县| 绥宁县| 大城县| 清苑县| 乌审旗| 桃园县| 乌鲁木齐县| 日喀则市| 赤水市| 商河县| 吕梁市| 饶河县| 乌鲁木齐县| 枞阳县| 惠东县| 家居| 武邑县| 屏边| 松溪县| 丰城市| 新乡县| 宝兴县| 维西| 永仁县| 台南市| 罗平县| 贵阳市| 桦川县| 江阴市| 武安市| 宝山区| 定边县| 无为县| 曲松县| 靖宇县| 尖扎县| 民乐县| 偏关县| 腾冲县|