Java中如何唤醒“指定的“某个线程
熟悉线程操作的小朋友应该知道,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态 } }