国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

編程(39)----------多線程中的鎖

這篇具有很好參考價(jià)值的文章主要介紹了編程(39)----------多線程中的鎖。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

假設(shè)一個(gè)這樣的場(chǎng)景: 在多線程的代碼中, 需要在不同的線程中對(duì)同一個(gè)變量進(jìn)行操作. 那此時(shí)就會(huì)出現(xiàn)問(wèn)題: 多線程是并發(fā)進(jìn)行的, 也就是說(shuō)代碼運(yùn)行的時(shí)候, 倆個(gè)線程會(huì)同時(shí)對(duì)一個(gè)變量進(jìn)行操作, 這樣就會(huì)涉及到多線程的安全問(wèn)題:

class Counter{
    public int count;

    public  void add(){
            count++;
    }
}
public class demo1 {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                counter.add();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                counter.add();
            }
        });
        t1.start();
        t2.start();

        t1.join();
        t2.join();
        System.out.println(counter.count);
    }
}

在這個(gè)代碼中, 兩個(gè)線程會(huì)分別對(duì)count進(jìn)行自增五千次, 按理說(shuō)最后打印的結(jié)果是一萬(wàn). 但實(shí)際上,多次運(yùn)行后代碼的結(jié)果,很難做到一萬(wàn), 常見(jiàn)于八九千的結(jié)果.?

其原因在于, add的過(guò)程并非不可拆分的, 也就是不具有原子性. 在實(shí)際的運(yùn)行中, add可以大致分為三步: 讀取, 加一, 最后再賦值. 當(dāng)然這并非專業(yè)的術(shù)語(yǔ)說(shuō)法, 這里只簡(jiǎn)單的以此為描述.?

由于兩個(gè)線程同時(shí)進(jìn)行, 也就是都要執(zhí)行這三步, 且是以搶占式進(jìn)行執(zhí)行. 那執(zhí)行順序就必然亂套了. 很可能會(huì)出現(xiàn)線程1剛將count原值讀入, 線程2就將其賦值走了, 根本沒(méi)來(lái)得及加一. 這種還未執(zhí)行完就將其讀入的操作, 也可稱其為臟讀.?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?編程(39)----------多線程中的鎖

?為避免這種亂套的多線程安全問(wèn)題, 常用辦法便是采用加鎖(Synchronized), 其用于修飾方法和代碼塊. 但是特別注意, 加鎖是鎖的對(duì)象. 當(dāng)某個(gè)對(duì)象加鎖后, 只有當(dāng)其再解鎖后, 另一個(gè)線程才能重新獲取鎖, 否者會(huì)陷入阻塞等待的狀態(tài):

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??編程(39)----------多線程中的鎖

?這樣的操作就能保證在執(zhí)行完一整個(gè)add后再執(zhí)行下一個(gè)add. 雖會(huì)降低運(yùn)行速率, 但能保證代碼的準(zhǔn)確性. 代碼上的修改只需將add進(jìn)行加鎖即可保證得到準(zhǔn)確的結(jié)果:

//只需在此處加鎖即可
    public synchronized void add(){
            count++;
    }
}

//或者代碼塊加鎖
    public void add(){
        synchronized (this) {
            count++;
        }
    }

? 若兩個(gè)線程針對(duì)不同對(duì)象加鎖或者一個(gè)加鎖一個(gè)不加鎖, 那么也不會(huì)存在阻塞等待的情況.

還有一種特殊情況: 多重鎖. 即一個(gè)線程加了兩把鎖, 雖然說(shuō)當(dāng)一個(gè)線程對(duì)對(duì)象上鎖后, 另一個(gè)線程是應(yīng)該阻塞等待的, 但此時(shí)若上鎖線程就是要訪問(wèn)的線程呢? 這時(shí)是否可以考慮開(kāi)綠燈呢? 這就好比小偷偷不屬于自己的東西, 這是不被允許的犯罪行為. 那如果他偷的是自己的東西呢? 這完全是可以的, 因?yàn)檫@壓根就不算偷竊.

因此, 對(duì)于可以實(shí)現(xiàn)多重鎖的關(guān)鍵字, 就被認(rèn)為是可重入的, 反之是不可重入. 在java中的synchronized是屬于可重入, 也就是說(shuō), 加上述代碼合并運(yùn)行, 仍可以得到正確的結(jié)果, 但并非所有的鎖都支持該功能:

 //可重入
    public synchronized void add(){
        synchronized (this) {
            count++;
        }
    }

若不支持可重入, 則會(huì)陷入死鎖狀態(tài), 卡在那里 一直阻塞等待.

當(dāng)然, 死鎖的狀態(tài)并非只有上述的這一種. 第二種是兩個(gè)線程兩把鎖, 即兩個(gè)線程先分別加鎖, 然后再嘗試獲得對(duì)方的鎖:

public class demo2 {
    public static void main(String[] args) {
        Object lock1 = new Object();
        Object lock2 = new Object();
        Thread t1 = new Thread(() -> {
            synchronized (lock1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (lock2){
                    System.out.println("獲取鎖2");
                }
            }
        });
        Thread t2 = new Thread(() -> {
            synchronized (lock2){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized ((lock1)){
                    System.out.println("獲取鎖1");
                }
            }
        });

        t1.start();
        t2.start();
    }
}

在這個(gè)代碼中就能夠看出, 當(dāng)兩個(gè)線程將鎖1 鎖2獲取后, 要相互獲取對(duì)方的鎖, 但對(duì)方的鎖未解鎖, 因此在這種情況想兩個(gè)線程都被阻塞, 不能繼續(xù)運(yùn)行. 在這種情況下代碼會(huì)一直處于運(yùn)行狀態(tài). 可以用jconsole觀察到線程是屬于阻塞狀態(tài).

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?編程(39)----------多線程中的鎖

?第三種死鎖即第二種死鎖的一般情況, 多線程多把鎖而非兩把鎖. 這里涉及到一個(gè)經(jīng)典的吃面問(wèn)題. 假設(shè), 有一個(gè)圓桌, 共坐了五個(gè)人, 每?jī)蓚€(gè)人之間, 放了一根筷子. 也就是說(shuō)共放了五根筷子.

假設(shè)吃面的人必須得先拿起他左邊的筷子, 再拿起他右邊的一根筷子. 那在這種情況下考慮極端情況, 當(dāng)五個(gè)人同時(shí)都想吃面時(shí), 會(huì)同時(shí)都拿起左邊的筷子, 且右邊沒(méi)有筷子可拿. 這個(gè)時(shí)候就僵住了, 誰(shuí)也吃不了面, 誰(shuí)也不會(huì)放下筷子. 同理, 在多線程種, 每個(gè)線程就好比每個(gè)人, 每跟筷子就好比每個(gè)鎖, 考慮極端情況, 會(huì)出現(xiàn)這種全部僵在一起的狀態(tài).

要解決這個(gè)問(wèn)題, 就得先了解死鎖的必要條件:\

1. 互斥使用. 線程一上鎖, 線程二只能等著.

2. 不可搶占. 線程一獲得鎖之后, 只能自己釋放鎖, 而不能由線程二強(qiáng)行獲取鎖

3.保持穩(wěn)定性. 若線程一已經(jīng)獲得鎖A, 它再嘗試獲得鎖B時(shí), 鎖A是不會(huì)因?yàn)榫€程一獲得鎖B而解鎖鎖A.

4.循環(huán)等待. 也就是剛才所演示的. 線程一獲得鎖A的同時(shí), 線程二獲得鎖B. 然后線程一要獲得鎖B, 線程二要獲得鎖A, 僵持不下.

對(duì)于Synchronized而言, 其實(shí)必要條件只有第四點(diǎn). 前三點(diǎn)是無(wú)法去改變的. 但對(duì)于其他鎖來(lái)說(shuō)不一定. 因此, 想要解決死鎖, 就只能從, 循環(huán)等待入手.

解決方法是, 給每一把鎖標(biāo)號(hào), 再按照標(biāo)號(hào)的一定順序進(jìn)行加鎖.

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??編程(39)----------多線程中的鎖

以吃面來(lái)舉例. 將每根筷子標(biāo)號(hào), 并規(guī)定拿筷子必須從小號(hào)開(kāi)始拿. 對(duì)應(yīng)多線程種按鎖的標(biāo)號(hào)順序由小到大加鎖. 這樣的話, 一號(hào)筷子和二號(hào)筷子之間的人就拿一號(hào), 二號(hào)筷子和三號(hào)筷子之間的人就拿二號(hào), 以此類推.

當(dāng)輪到一號(hào)筷子和五號(hào)筷子之間的人拿筷子時(shí), 出現(xiàn)問(wèn)題了. 由于規(guī)定按小號(hào)拿, 因此應(yīng)該是拿一號(hào)筷子而非五號(hào)筷子. 但此時(shí)的一號(hào)筷子已經(jīng)被占用. 因此他只能等待, 也就是多線程中的阻塞. 與此同時(shí), 前一個(gè)人可以再拿到四號(hào)筷子的基礎(chǔ)上拿到五號(hào)筷子, 也就是獲取到鎖, 從而執(zhí)行多線程. 以這種方式, 就不會(huì)出現(xiàn)所有人都吃不到面, 避免所有線程都處于阻塞狀態(tài). 反應(yīng)到代碼中, 就只需將鎖調(diào)換一下即可:

public class demo2 {
    public static void main(String[] args) {
        Object lock1 = new Object();
        Object lock2 = new Object();
        //標(biāo)號(hào): 鎖1 為一號(hào), 鎖2 為二號(hào). 由小到大加鎖
        Thread t1 = new Thread(() -> {
            synchronized (lock1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized (lock2){
                    System.out.println("獲取鎖2");
                }
            }
        });
        Thread t2 = new Thread(() -> {
            synchronized (lock1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                synchronized ((lock2)){
                    System.out.println("獲取鎖1");
                }
            }
        });

        t1.start();
        t2.start();
    }
}

除此以外, 解決這類問(wèn)題還可以使用銀行家算法. 但是在實(shí)際工作中, 使用并不廣泛. 因?yàn)槠溥^(guò)于復(fù)雜, 實(shí)用性不高.

-------------------------------------------最后編輯于2023.6.1 下午兩點(diǎn)左右文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-468400.html

到了這里,關(guān)于編程(39)----------多線程中的鎖的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • StampedLock:高并發(fā)場(chǎng)景下一種比讀寫鎖更快的鎖

    摘要: 在讀多寫少的環(huán)境中,有沒(méi)有一種比ReadWriteLock更快的鎖呢?有,那就是JDK1.8中新增的StampedLock! 本文分享自華為云社區(qū)《【高并發(fā)】高并發(fā)場(chǎng)景下一種比讀寫鎖更快的鎖》,作者: 冰 河。 ReadWriteLock鎖允許多個(gè)線程同時(shí)讀取共享變量,但是在讀取共享變量的時(shí)候,不

    2024年02月07日
    瀏覽(18)
  • C++多線程場(chǎng)景中的變量提前釋放導(dǎo)致棧內(nèi)存異常

    C++多線程場(chǎng)景中的變量提前釋放導(dǎo)致棧內(nèi)存異常

    在子線程中嘗試使用當(dāng)前函數(shù)的資源 ,是非常危險(xiǎn)的,但是C++支持這么做。因此C++這么做可能會(huì)造成棧內(nèi)存異常。 上述是一個(gè)正常的多線程代碼。 但是如果將其中多線程傳參設(shè)置為引用傳遞,可能就會(huì)造成棧內(nèi)存異常了,如下所示: 編譯成功,但是運(yùn)行失敗。 運(yùn)行結(jié)果:

    2024年02月13日
    瀏覽(43)
  • Java多線程編程中的線程死鎖

    Java多線程編程中的線程死鎖

    ? 在多線程編程中,線程死鎖是一種常見(jiàn)的問(wèn)題,它發(fā)生在兩個(gè)或多個(gè)線程互相等待對(duì)方釋放資源的情況下,導(dǎo)致程序無(wú)法繼續(xù)執(zhí)行 。本文將介紹線程死鎖的概念、產(chǎn)生原因、示例以及如何預(yù)防和解決線程死鎖問(wèn)題。 線程死鎖的概念 ? 線程死鎖是指兩個(gè)或多個(gè)線程被阻塞

    2024年02月12日
    瀏覽(28)
  • Java多線程編程中的線程同步

    Java多線程編程中的線程同步

    基本概念: ? 線程同步是多線程編程中的一個(gè)重要概念,用于控制多個(gè)線程對(duì)共享資源的訪問(wèn),以防止數(shù)據(jù)的不一致性和并發(fā)問(wèn)題。 在多線程環(huán)境下,多個(gè)線程同時(shí)訪問(wèn)共享資源可能導(dǎo)致數(shù)據(jù)的競(jìng)爭(zhēng)和不正確的結(jié)果。 是確保多個(gè)線程按照特定的順序和規(guī)則訪問(wèn)共享資源,以

    2024年02月13日
    瀏覽(28)
  • InnoDB鎖初探(一):鎖分類和RR不同場(chǎng)景下的鎖機(jī)制

    InnoDB鎖初探(一):鎖分類和RR不同場(chǎng)景下的鎖機(jī)制

    數(shù)據(jù)庫(kù)鎖是Mysql實(shí)現(xiàn)數(shù)據(jù)一致性的基礎(chǔ)之一,是在事務(wù)的基礎(chǔ)之上,基于Mysql Server層或存儲(chǔ)引擎層實(shí)現(xiàn)的。 前置條件: 查看語(yǔ)句: 按照鎖的粒度,可以分為表鎖和行鎖 共享鎖 排他鎖 意向鎖是表級(jí)的 同樣具有意向共享鎖(IS)、意向排他鎖(IX) TABLE LOCK table *** trx id *** lo

    2024年02月09日
    瀏覽(15)
  • 多線程編程之——終止(打斷)正在執(zhí)行中的線程

    多線程編程之——終止(打斷)正在執(zhí)行中的線程

    ps:文字有點(diǎn)多,想看結(jié)果的,直接跳轉(zhuǎn):《二》 把線程交給spring管理好不好? 將線程交給Spring管理是一個(gè)常見(jiàn)的做法,特別是在基于Spring的應(yīng)用程序中。通過(guò)將線程納入Spring的管理范圍,你可以利用Spring的依賴注入和生命周期管理功能,更好地控制線程的生命周期和資源。

    2024年02月05日
    瀏覽(13)
  • C# 中的多線程和異步編程

    C# 中的多線程和異步編程

    最近在看代碼的過(guò)程中,發(fā)現(xiàn)有很多地方涉及到多線程、異步編程,這是比較重要且常用的知識(shí)點(diǎn),而本人在這方面還理解尚淺,因此開(kāi)始全面學(xué)習(xí)C#中的多線程和異步編程,文中部分內(nèi)容摘抄自一位前輩的網(wǎng)站:網(wǎng)址鏈接,為了更便于理解和學(xué)習(xí),本人還在個(gè)別地方做了一

    2023年04月08日
    瀏覽(22)
  • 一文讀懂flutter線程: 深入了解Flutter中的多線程編程

    一文讀懂flutter線程: 深入了解Flutter中的多線程編程

    在移動(dòng)應(yīng)用開(kāi)發(fā)領(lǐng)域,F(xiàn)lutter已經(jīng)成為了一個(gè)備受歡迎的框架,用于創(chuàng)建高性能、跨平臺(tái)的應(yīng)用程序。Flutter的一個(gè)關(guān)鍵特性是其能夠輕松處理多線程編程,以改進(jìn)應(yīng)用程序的性能和響應(yīng)性。本文將深入探討Flutter中的多線程編程,包括為什么需要多線程、如何在Flutter中創(chuàng)建和管

    2024年01月20日
    瀏覽(26)
  • Android中的多線程編程與異步處理

    Android中的多線程編程與異步處理

    在移動(dòng)應(yīng)用開(kāi)發(fā)中,用戶體驗(yàn)是至關(guān)重要的。一個(gè)流暢、高效的應(yīng)用能夠吸引用戶并提升用戶滿意度。然而,移動(dòng)應(yīng)用面臨著處理復(fù)雜業(yè)務(wù)邏輯、響應(yīng)用戶輸入、處理網(wǎng)絡(luò)請(qǐng)求等多個(gè)任務(wù)的挑戰(zhàn)。為了確保應(yīng)用的性能和用戶體驗(yàn),多線程編程和異步處理成為了不可或缺的技術(shù)

    2024年02月11日
    瀏覽(23)
  • Java - JUC(java.util.concurrent)包詳解,其下的鎖、安全集合類、線程池相關(guān)、線程創(chuàng)建相關(guān)和線程輔助類、阻塞隊(duì)列

    Java - JUC(java.util.concurrent)包詳解,其下的鎖、安全集合類、線程池相關(guān)、線程創(chuàng)建相關(guān)和線程輔助類、阻塞隊(duì)列

    JUC是java.util.concurrent包的簡(jiǎn)稱,在Java5.0添加,目的就是為了更好的支持高并發(fā)任務(wù)。讓開(kāi)發(fā)者進(jìn)行多線程編程時(shí)減少競(jìng)爭(zhēng)條件和死鎖的問(wèn)題 java.lang.Thread.State tools(工具類):又叫信號(hào)量三組工具類,包含有 CountDownLatch(閉鎖) 是一個(gè)同步輔助類,在完成一組正在其他線程中

    2024年02月05日
    瀏覽(22)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包