10章 - 多線(xiàn)程并發(fā)擴(kuò)展

死鎖 - 必要條件

互斥條件:進(jìn)程要求對(duì)所分配的資源(如打印機(jī))進(jìn)行排他性控制,即在一段時(shí)間內(nèi)某資源僅為一個(gè)進(jìn)程所占有。此時(shí)若有其他進(jìn)程請(qǐng)求該資源,則請(qǐng)求進(jìn)程只能等待。
請(qǐng)求和保持條件:進(jìn)程已經(jīng)保持了至少一個(gè)資源,但又提出了新的資源請(qǐng)求,而該資源已被其他進(jìn)程占有,此時(shí)請(qǐng)求進(jìn)程被阻塞,但對(duì)自己已獲得的資源保持不放。
不剝奪條件:進(jìn)程所獲得的資源在未使用完畢之前,不能被其他進(jìn)程強(qiáng)行奪走,即只能由獲得該資源的進(jìn)程自己來(lái)釋放(只能是主動(dòng)釋放)。
環(huán)路等待條件:存在一種進(jìn)程資源的循環(huán)等待鏈,鏈中每一個(gè)進(jìn)程已獲得的資源同時(shí)被鏈中下一個(gè)進(jìn)程所請(qǐng)求。即存在一個(gè)處于等待狀態(tài)的進(jìn)程集合{Pl, P2, ..., pn},其中Pi等 待的資源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的資源被P0占有,如圖1所示。

代碼演示:

/**
 * 一個(gè)簡(jiǎn)單的死鎖類(lèi)
 * 當(dāng)DeadLock類(lèi)的對(duì)象flag==1時(shí)(td1),先鎖定o1,睡眠500毫秒
 * 而td1在睡眠的時(shí)候另一個(gè)flag==0的對(duì)象(td2)線(xiàn)程啟動(dòng),先鎖定o2,睡眠500毫秒
 * td1睡眠結(jié)束后需要鎖定o2才能繼續(xù)執(zhí)行,而此時(shí)o2已被td2鎖定;
 * td2睡眠結(jié)束后需要鎖定o1才能繼續(xù)執(zhí)行,而此時(shí)o1已被td1鎖定;
 * td1、td2相互等待,都需要得到對(duì)方鎖定的資源才能繼續(xù)執(zhí)行,從而死鎖。
 */

@Slf4j
public class DeadLock implements Runnable {
    public int flag = 1;
    //靜態(tài)對(duì)象是類(lèi)的所有對(duì)象共享的
    private static Object o1 = new Object(), o2 = new Object();

    @Override
    public void run() {
        log.info("flag:{}", flag);
        if (flag == 1) {
            synchronized (o1) {
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (o2) {
                    log.info("1");
                }
            }
        }
        if (flag == 0) {
            synchronized (o2) {
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (o1) {
                    log.info("0");
                }
            }
        }
    }

    public static void main(String[] args) {
        DeadLock td1 = new DeadLock();
        DeadLock td2 = new DeadLock();
        td1.flag = 1;
        td2.flag = 0;
        //td1,td2都處于可執(zhí)行狀態(tài),但JVM線(xiàn)程調(diào)度先執(zhí)行哪個(gè)線(xiàn)程是不確定的。
        //td2的run()可能在td1的run()之前運(yùn)行
        new Thread(td1).start();
        new Thread(td2).start();
    }
}

多線(xiàn)程并發(fā)最佳實(shí)踐

使用本地變量
使用不可變類(lèi)
最小化鎖的作用于范圍:S=1/(1-a+a/n)
使用線(xiàn)程池的Executor,而不是直接new Thread執(zhí)行
寧可使用同步也不要使用線(xiàn)程的wait和notify
使用BlockingQueue實(shí)現(xiàn)生產(chǎn)-消費(fèi)模式
使用并發(fā)集合而不是加了鎖的同步集合
使用Semaphore創(chuàng)建有界的訪(fǎng)問(wèn)
寧可使用同步代碼塊,也不要使用同步的方法
避免使用靜態(tài)變量

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 又來(lái)到了一個(gè)老生常談的問(wèn)題,應(yīng)用層軟件開(kāi)發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢? 今天就這個(gè)問(wèn)題開(kāi)始,來(lái)談?wù)劜?..
    tangsl閱讀 4,324評(píng)論 0 23
  • 1.內(nèi)存的頁(yè)面置換算法 (1)最佳置換算法(OPT)(理想置換算法):從主存中移出永遠(yuǎn)不再需要的頁(yè)面;如無(wú)這樣的...
    杰倫哎呦哎呦閱讀 3,596評(píng)論 1 9
  • 1. 基礎(chǔ)知識(shí) 1.1、 基本概念、 功能 馮諾伊曼體系結(jié)構(gòu)1、計(jì)算機(jī)處理的數(shù)據(jù)和指令一律用二進(jìn)制數(shù)表示2、順序執(zhí)...
    yunpiao閱讀 5,804評(píng)論 1 22
  • 進(jìn)程和線(xiàn)程 進(jìn)程 所有運(yùn)行中的任務(wù)通常對(duì)應(yīng)一個(gè)進(jìn)程,當(dāng)一個(gè)程序進(jìn)入內(nèi)存運(yùn)行時(shí),即變成一個(gè)進(jìn)程.進(jìn)程是處于運(yùn)行過(guò)程中...
    勝浩_ae28閱讀 5,259評(píng)論 0 23
  • 在開(kāi)發(fā)Java多線(xiàn)程應(yīng)用程序中,各個(gè)線(xiàn)程之間由于要共享資源,必須用到鎖機(jī)制。Java提供了多種多線(xiàn)程鎖機(jī)制的實(shí)現(xiàn)方...
    千淘萬(wàn)漉閱讀 7,112評(píng)論 1 33

友情鏈接更多精彩內(nèi)容