併發編程之第四篇

4.11 多把鎖

一間大屋子有兩個功能 : 睡覺、學習、互不相干
如今小南要學習,小女要睡覺,但若是隻用一間屋子(一個對象鎖)的話,那麼併發度很低
解決方法時準備多個房間(多個對象鎖)
在這裏插入圖片描述java

4.12 活躍性

死鎖
有這樣的狀況 : 一個線程須要同時獲取多把鎖,這時就容易發生死鎖
t1 線程得到A對象鎖,接下來想獲取B對象的鎖
t2 線程獲取B對象鎖,接下來想獲取A對象的鎖
在這裏插入圖片描述
定位死鎖web

  • 檢測死鎖可使用jconsole工具,或者使用jps定位進程id,再用jstack定位死鎖 :
    在這裏插入圖片描述
    在這裏插入圖片描述

飢餓

先來看看一個線程飢餓的例子,使用順序加鎖的方式解決以前的死鎖問題
在這裏插入圖片描述
順序加鎖的解決方案
在這裏插入圖片描述編程

4.13 ReentrantLock

相對於synchronized它具有以下特色併發

  • 可中斷
  • 可設置超時時間
  • 能夠設置爲公平鎖
  • 支持多個條件變量
    與synch同樣,都支持可重入
    可重入
    可重入是指用一個線程若是首次得到了這把鎖,那麼由於它是這把鎖的擁有者,所以有權利再次獲取這把鎖
    若是是不可重入鎖,那麼第二次得到鎖時,本身也會被鎖擋住
    基本語法
    在這裏插入圖片描述

同步模式之順序控制

固定運行順序
好比,必須先2後1打印
wait notify版
在這裏插入圖片描述
在這裏插入圖片描述svg

交替輸出

線程1輸出a5次,線程2輸出b5次,線程3輸出c5次。如今要去輸出abcabcabcabcabc怎麼實現工具

package com.example.demo;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Test27 {
    public static void main(String[] args) {
        WaitNotify waitNotify = new WaitNotify(1, 5);
        new Thread(() -> {
            waitNotify.print("a", 1, 2);
        }).start();
        new Thread(() -> {
            waitNotify.print("b", 2, 3);
        }).start();
        new Thread(() -> {
            waitNotify.print("c", 3, 1);
        }).start();
    }
}

/**
 * 輸出內容         等待標記        下一個標記
 * a                1               2
 * b                2               3
 * c                3               1
 */
class WaitNotify {

    /**
     * 打印
     * @param str
     * @param waitFlag
     * @param nextFLag
     */
    public void print(String str, int waitFlag, int nextFLag) {
        for (int i = 0; i < loopNumber; i++) {
            synchronized (this) {
                while (flag != waitFlag) {
                    try {
                        this.wait();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(str);
                flag = nextFLag;
                this.notifyAll();
            }
        }
    }

    /**
     * 等待標記
     */
    private int flag;

    /**
     * 循環次數
     */
    private int loopNumber;

    public WaitNotify(int flag, int loopNumber) {
        this.flag = flag;
        this.loopNumber = loopNumber;
    }
}
package com.example.demo;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Test2 {
    public static void main(String[] args) throws InterruptedException {
        AwaitSignal awaitSignal = new AwaitSignal(5);
        Condition a = awaitSignal.newCondition();
        Condition b = awaitSignal.newCondition();
        Condition c = awaitSignal.newCondition();
        new Thread(() -> {
            awaitSignal.print("a", a, b);
        }).start();
        new Thread(() -> {
            awaitSignal.print("b", b, c);
        }).start();
        new Thread(() -> {
            awaitSignal.print("c", c, a);
        }).start();

        Thread.sleep(1000);
        awaitSignal.lock();
        try {
            System.out.println("開始。。。。");
            a.signal();
        } finally {
            awaitSignal.unlock();
        }
    }
}

class AwaitSignal extends ReentrantLock {
    private int loopNumber;

    public AwaitSignal(int loopNumber) {
        this.loopNumber = loopNumber;
    }

    /**
     * 參數1 打印內容,參數2 進入那一間休息室,參數3 下一間休息室
     * @param str
     * @param current
     * @param next
     */
    public void print(String str, Condition current, Condition next) {
        for (int i = 0; i < loopNumber; i++) {
            lock();
            try {
                current.await();
                System.out.println(str);
                next.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                unlock();
            }
        }
    }

}

本文同步分享在 博客「不同的花朵」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。oop

相關文章
相關標籤/搜索