服务器测评网
我们一直在努力

Java中线程调用wait()后如何正确解除等待状态避免死锁?

在Java编程中,“等待”是并发场景下的常见操作,无论是线程间的协调、任务执行的控制,还是资源同步,都离不开对等待状态的管理,合理解除等待状态,能避免线程阻塞、资源浪费,甚至死锁等问题,本文将从线程等待、任务等待、锁等待等常见场景出发,详细解析Java中解除等待的方法及注意事项。

Java中线程调用wait()后如何正确解除等待状态避免死锁?

线程等待:wait/notify与中断机制

线程等待最典型的场景是通过Object.wait()Object.notify()/notifyAll()实现。wait()会让当前线程释放锁并进入等待状态,直到其他线程调用notify()(唤醒任意一个等待线程)或notifyAll()(唤醒所有等待线程),但解除等待需注意以下几点:

正确使用同步块

wait()notify()必须在synchronized块或方法中调用,否则会抛出IllegalMonitorStateException

synchronized (obj) {
    while (condition不满足) { // 使用while避免虚假唤醒
        obj.wait();
    }
    // 执行后续逻辑
}

其他线程通过synchronized (obj)获取锁后,可调用obj.notify()唤醒等待线程:

synchronized (obj) {
    condition = true; // 修改条件
    obj.notify(); // 或notifyAll()
}

响应中断:避免无限等待

线程在等待期间可能被Thread.interrupt()中断,此时wait()会抛出InterruptedException,并清除中断状态,需捕获异常并处理中断逻辑,

synchronized (obj) {
    try {
        while (!condition) {
            obj.wait(); // 被中断时抛出异常
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt(); // 恢复中断状态
        System.out.println("等待被中断,退出等待");
        return;
    }
}

任务等待:Future与线程池控制

在异步编程中,Future代表异步任务的结果,Future.get()会让当前线程阻塞直到任务完成或超时,解除等待可通过以下方式:

Java中线程调用wait()后如何正确解除等待状态避免死锁?

取消任务:Future.cancel()

调用future.cancel(true)可尝试中断正在执行的任务(若任务未开始则直接取消)。

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() -> {
    Thread.sleep(2000);
    return "任务完成";
});
// 1秒后取消任务
Thread.sleep(1000);
boolean cancelled = future.cancel(true); 
System.out.println("任务是否取消:" + cancelled); 

若任务已执行完毕,cancel()返回false;若任务正在执行且参数为true,会尝试中断线程(需任务响应中断)。

超时等待:Future.get(timeout)

避免无限阻塞,可设置超时时间,超时后抛出TimeoutException

try {
    String result = future.get(1, TimeUnit.SECONDS); // 最多等待1秒
    System.out.println(result);
} catch (TimeoutException e) {
    System.out.println("等待超时");
    future.cancel(true); // 超时后取消任务
}

锁等待:Lock与Condition的精确控制

除了synchronizedjava.util.concurrent.locks.Lock提供了更灵活的锁机制,其Condition对象支持更精细的等待/唤醒控制。

Lock.lockInterruptibly()响应中断

lock()会一直等待直到获取锁,而lockInterruptibly()允许在等待期间响应中断:

Java中线程调用wait()后如何正确解除等待状态避免死锁?

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
try {
    lock.lockInterruptibly(); // 可被中断的锁获取
    while (!condition满足) {
        condition.await(); // 类似wait(),需在lock()中调用
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    System.out.println("获取锁时被中断");
} finally {
    if (lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}

其他线程通过condition.signal()condition.signalAll()唤醒等待线程:

lock.lock();
try {
    condition = true;
    condition.signal(); // 唤醒一个等待线程
} finally {
    lock.unlock();
}

其他场景的等待解除

Thread.sleep()的等待

Thread.sleep()是静态方法,让线程休眠指定时间,期间可通过interrupt()中断,抛出InterruptedException

Thread.sleep(1000); // 休眠1秒
// 若线程被中断,sleep()会立即抛出异常

CountDownLatch与CyclicBarrier

  • CountDownLatch:通过countDown()减少计数,当计数为0时,等待的await()方法解除阻塞。
  • CyclicBarrier:通过await()等待所有线程到达屏障,可通过reset()重置或breakBarrier()中断等待。

Java中解除等待的核心思路是“主动唤醒”或“被动中断”:

  • 主动唤醒:通过notify()signal()countDown()等方法,在条件满足时通知等待线程;
  • 被动中断:通过Thread.interrupt()中断线程,或使用Future.cancel()lockInterruptibly()等支持中断的机制。
    无论哪种方式,都需注意线程安全、避免虚假唤醒、正确处理中断状态,并确保同步锁的获取与释放配对,才能高效、安全地解除等待状态。
赞(0)
未经允许不得转载:好主机测评网 » Java中线程调用wait()后如何正确解除等待状态避免死锁?