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