JUC(六)--執行緒等待

如何中斷一個執行緒在之前的文章中說過了,傳送門。今日聊聊執行緒等待那些事。

一共有三種讓執行緒等待和喚醒的方法

使用Object中的wait方法讓執行緒等待,使用Object中的notify方法喚醒執行緒

使用JUC包中Condition的await方法讓執行緒等待,signal方法喚醒執行緒

使用LockSupport類阻塞當前執行緒以及喚醒被指定被阻塞的執行緒

wait和notify的使用姿勢

wait和notify方法必須要在同步塊或者方法裡面,且成對出現使用,如果不放在同步塊裡面會報IllegalMonitorStateException。

要先wait後notify,否則執行緒無法被喚醒

private final static String LOCK = “lock”;@Testpublic void testWait() throws InterruptedException { Thread t1 = new Thread(() -> { log。info(“進入t1執行緒”); synchronized (LOCK) { try { log。info(“t1執行緒開始等待”); LOCK。wait(); } catch (InterruptedException e) { e。printStackTrace(); } log。info(“t1執行緒繼續執行”); } }); t1。start(); Thread。sleep(1000); synchronized (LOCK) { log。info(“喚醒t1執行緒”); LOCK。notify(); }}

JUC(六)--執行緒等待

Condition的使用姿勢

condition的使用方式其實跟wait,notify差不多,都是需要先加鎖,並且需要先await後signal,順序不能反了。區別就是一個鎖支援多個條件變數。之前的文章有具體案例,傳送門

LockSupport的使用姿勢

之前兩種方式都需要先加鎖後等待,並且等待和喚醒的順序不能錯了,而LockSupport就沒有這兩種限制,可以在不加鎖的情況下使用,並且等待和喚醒不要求先後順序。

LockSupport是用來建立鎖和其他同步類的基本執行緒阻塞原語。

LockSupport類使用了一種名為Permit(許可)的概念來做到阻塞和喚醒執行緒的功能, 每個執行緒都有一個許可(permit),

permit只有兩個值1和零,預設是零。

可以把許可看成是一種(0,1)訊號量(Semaphore),但與 Semaphore 不同的是,許可的累加上限是1。

呼叫LockSupport。pack時,permit預設是零,所以一開始呼叫park()方法,當前執行緒就會阻塞,直到別的執行緒將當前執行緒的permit設定為1時,park方法會被喚醒,然後會將permit再次設定為零並返回。如果permit不為0則繼續執行,不會阻塞

呼叫unpark(thread)方法後,就會將thread執行緒的許可permit設定成1(注意多次呼叫unpark方法,不會累加,permit值還是1)會自動喚醒thread執行緒,即之前阻塞中的LockSupport。park()方法會立即返回。

public void testPark() throws InterruptedException { Thread t1 = new Thread(() -> { log。info(“進入t1執行緒”); log。info(“t1執行緒正在獲取許可”); LockSupport。park(); log。info(“t1執行緒開始執行”); }); t1。start(); Thread。sleep(1000); log。info(“頒發t1執行緒許可”); LockSupport。unpark(t1);}

JUC(六)--執行緒等待

可以看到程式碼簡潔了很多。LockSupport還有個需要注意的地方是如果在同步塊中執行,它是不會釋放鎖的,而前面兩種方式會釋放鎖。