熟悉線程操作的小朋友應該知道,Java中線程的掛起和喚醒一般用synchronized + wait + notify完成。
比如:
synchronized(o) { o.wait(); //wait狀態 }
在其他線程中o.notify(),就可以喚醒在o上wait的線程。
可是如果o上有多個線程wait,是沒有辦法喚醒“指定”的某個線程的。
import java.util.concurrent.TimeUnit; public class TestNotify extends Thread{ public static void main(String[] args) { final Object synObj = new Object(); Thread t1 = new Thread(new Runnable() { @Override public void run() { synchronized(synObj) { System.out.println("1.T1獲取synObj的對象監視器,開始執行同步塊"); try { TimeUnit.SECONDS.sleep(2);//休息一分鍾,不放棄鎖 System.out.println("T1在 wait()時掛起了"); synObj.wait(); System.out.println("T1被其他線程喚醒后並重新獲得synObj的對象監視器,繼續執行"); }catch(InterruptedException e) { e.printStackTrace(); } System.out.println("T1獲取synObj的對象監視器,結束同步塊"); } }; }); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { System.out.println("T2啟動,但是因為有別的線程占用了synObj的對象監視器,則等待別的線程執行synObj.wait來釋放它"); synchronized(synObj) { try { System.out.println("T2獲取synObj的對象監視器,進入同步塊"); synObj.notify(); System.out.println("T2執行synObj.notify()"); TimeUnit.SECONDS.sleep(2); System.out.println("T2結束同步塊,釋放synObj的對象監視器"); }catch(InterruptedException e) { e.printStackTrace(); } } }; }); t2.start(); Thread t3 = new Thread(new Runnable() { @Override public void run() { System.out.println("T3啟動,但是因為有別的線程占用了synObj的對象監視器,則等待別的線程執行synObj.wait來釋放它"); synchronized(synObj) { try { System.out.println("T3獲取synObj的對象監視器,進入同步塊"); synObj.notify(); System.out.println("T3執行synObj.notify()"); TimeUnit.SECONDS.sleep(2); System.out.println("T3結束同步塊,釋放synObj的對象監視器"); }catch(InterruptedException e) { e.printStackTrace(); } } }; }); t3.start(); } }
(2)使用Lock + Condition 實現喚醒指定的部分線程
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Test { public static Lock lock = new ReentrantLock(); public static int count = 0; public static Condition conditionA = lock.newCondition(); public static Condition conditionB = lock.newCondition(); public static void main(String[] args) { Thread t1 = new Thread() { @Override public void run() { lock.lock(); if (count < 5) { System.out.println("線程1未達到業務要求,暫停中,等待線程2處理到達到要求后喚醒"); try { conditionA.await();// 暫停線程並釋放鎖 System.out.println("conditionA被喚醒"); conditionB.await(); System.out.println("conditionB被喚醒"); System.out.println("我是線程1后面的代碼"); } catch (InterruptedException e) { e.printStackTrace(); } } lock.unlock(); } }; Thread t2 = new Thread() { @Override public void run() { lock.lock(); while (count < 10) { count++; System.out.println("線程2業務處理中: " + count); try { Thread.sleep(1000); if (count == 5) { conditionA.signal(); System.out.println("喚醒線程1"); lock.unlock();// 調用signal()方法后,線程2並不會釋放鎖,需要手動釋放線程2才會執行 } } catch (InterruptedException e) { e.printStackTrace(); } } try { lock.lock();// 不加這個會報java.lang.IllegalMonitorStateException System.out.println("等待3秒后conditionB會被喚醒"); Thread.sleep(3000); conditionB.signal(); } catch (InterruptedException e) { e.printStackTrace(); } lock.unlock();// 這里釋放鎖,線程2執行完,線程1才會執行 } }; t1.start(); t2.start(); } }
console輸出:
(3) 使用Java6引入的LockSupport這個類。
import java.util.concurrent.locks.LockSupport; public class TestLockSupport { public static void main(String[] args) throws InterruptedException { Thread t = new Thread(()->{ System.out.println("start"); LockSupport.park(); //一直wait System.out.println("continue"); }); t.start(); Thread.sleep(2000); LockSupport.unpark(t); //指定t線程解除wait態 } }