问:JAVA中唤醒阻塞的线程有哪些?
在Java中,唤醒阻塞线程的方法有多种,以下是常见的线程唤醒方法。
唤醒方法
- 使用notify()和notifyAll()方法
synchronized (obj) {obj.notify(); // 唤醒单个等待线程// obj.notifyAll(); // 唤醒所有等待线程
}
- 使用interrupt()方法
Thread thread = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {System.out.println("Thread is interrupted");}
});thread.start();
thread.interrupt(); // 中断线程,唤醒阻塞
- 使用LockSupport.unpark()方法
Thread thread = new Thread(() -> LockSupport.park()); // 线程阻塞thread.start();
LockSupport.unpark(thread); // 唤醒阻塞线程
- 使用Condition的signal()和signalAll()方法
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();new Thread(() -> {lock.lock();try {condition.await(); // 线程等待} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}
}).start();// 唤醒线程
lock.lock();
try {condition.signal(); // 或使用condition.signalAll();
} finally {lock.unlock();
}
- 使用Semaphore的release()方法
Semaphore semaphore = new Semaphore(0);new Thread(() -> {try {semaphore.acquire(); // 线程阻塞} catch (InterruptedException e) {e.printStackTrace();}
}).start();semaphore.release(); // 释放许可,唤醒线程
- 使用CountDownLatch的countDown()方法
CountDownLatch latch = new CountDownLatch(1);new Thread(() -> {try {latch.await(); // 线程阻塞} catch (InterruptedException e) {e.printStackTrace();}
}).start();latch.countDown(); // 计数减一,唤醒线程
差异
方法 | 工作原理 | 适用场景 | 优点 | 缺点 | 使用场景示例 |
---|---|---|---|---|---|
notify()/notifyAll() | 唤醒等待线程 | 需要在synchronized块中使用,适用于简单等待/通知模式 | 简单易用,直接唤醒 | 容易导致死锁,不可中断等待 | 生产者-消费者问题 |
interrupt() | 中断线程 | 适用于任何阻塞状态(如sleep, wait, join) | 可中断线程,灵活性强 | 需要处理InterruptedException异常 | 长时间等待时中断线程 |
LockSupport.unpark() | 唤醒指定线程 | 不依赖于锁,可灵活控制线程 | 不需要持有锁,性能较好 | 可能导致未预期的行为,如重复唤醒 | 需要精确控制线程唤醒时 |
Condition.signal()/signalAll() | 唤醒等待条件线程 | 适用于更复杂的等待/通知模式,与Lock配合使用 | 更灵活,可精确控制唤醒条件 | 需要持有锁,可能导致死锁 | 复杂的生产者-消费者问题 |
Semaphore.release() | 释放许可唤醒线程 | 适用于控制资源访问的并发数量 | 可控制并发数,灵活性强 | 需要管理许可数量,可能导致资源泄露 | 资源池,限流器 |
CountDownLatch.countDown() | 计数减一唤醒线程 | 适用于等待多个线程完成后再执行后续操作 | 可精确控制线程等待数量 | 不可重用,一次性使用 | 多线程并行计算后汇总结果 |
结语
-
notify()/notifyAll():这两个方法用于唤醒在对象监视器上等待的线程。
notify()
唤醒单个线程,notifyAll()
唤醒所有线程。它们必须在synchronized
块中使用,因为依赖于对象锁。 -
interrupt():
interrupt()
方法用于中断线程,如果线程在等待、休眠或其他阻塞状态,会抛出InterruptedException
异常,从而唤醒线程。这种方法灵活性强,可以中断任何阻塞状态的线程。 -
LockSupport.unpark():
LockSupport
提供了更底层的线程阻塞和唤醒原语。unpark()
方法可以唤醒处于阻塞状态的指定线程,不依赖于对象锁,因此使用更简单灵活。 -
Condition.signal()/signalAll():
Condition
接口提供了更灵活的线程等待/通知模式。与Lock
配合使用,可以精确控制唤醒条件,适用于更复杂的并发场景。 -
Semaphore.release():
Semaphore
是一种计数信号量,用于控制对资源的并发访问数量。release()
方法释放一个许可,从而唤醒等待资源的线程。 -
CountDownLatch.countDown():
CountDownLatch
是一种同步帮助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程等待。countDown()
方法递减计数器的值,当计数到达零时,唤醒所有等待的线程。