Object.wait 和 Object.join 的区别

Object.wait()Thread.join() 是 Java 中用于线程间协作的两种机制,它们虽然看起来有相似的行为(阻塞线程的执行),但作用和使用场景完全不同。为了更好地理解它们的区别,我们需要深入探讨它们的原理、使用场景和底层机制。

1. Object.wait() 的作用与原理

Object.wait() 是 Java 中用于实现线程 同步线程间通信 的一种机制。它与 notify()notifyAll() 搭配使用,主要用于 等待某个条件的变化

1.1 使用场景

wait() 通常在 共享资源 的访问中使用,尤其是在多个线程同时操作同一个对象时:

  • 当某个线程无法继续执行(通常是因为条件不满足)时,它可以调用 wait() 进入 等待状态,直到其他线程修改了该条件并调用 notify()notifyAll()
  • wait() 必须在 同步块同步方法 中调用,且它会 释放持有的锁,允许其他线程继续执行。

1.2 wait() 的底层原理

wait() 的执行流程可以概括为以下几步:

  1. 进入同步块wait() 必须在持有某个对象锁的情况下执行,即需要在 synchronized 块中调用。
  2. 释放锁并阻塞:当 wait() 被调用时,当前线程会 释放当前对象的锁 并进入 阻塞状态,直到其他线程调用 notify()notifyAll() 来唤醒它。
  3. 唤醒:当某个线程调用了 notify()notifyAll() 后,正在等待该对象锁的线程会被唤醒。
  4. 重新获取锁:被唤醒的线程在继续执行之前必须 重新获得该对象的锁,只有当它获取到锁后,才会继续执行 wait() 之后的代码。
javaCopy codesynchronized (sharedObject) {
    while (!condition) {
        sharedObject.wait(); // 当前线程进入等待状态,并释放锁
    }
    // 继续执行其他操作
}

1.3 wait()notify() 的配合

  • notify():唤醒正在等待该对象锁的 一个线程。
  • notifyAll():唤醒所有正在等待该对象锁的线程。

1.4 关键点

  • wait() 必须在 synchronized 块中调用,并且调用 wait() 的对象就是持有的锁对象。
  • wait() 调用后,线程会 释放锁 并进入 等待队列,直到被其他线程唤醒。
  • notify()/notifyAll() 是用于唤醒等待的线程。

2. Thread.join() 的作用与原理

Thread.join() 是 Java 中用于 线程控制 的一种机制,它用于 等待另一个线程的结束

2.1 使用场景

join() 通常在需要保证某个线程 执行完毕 后,才继续执行当前线程的情况下使用。例如,主线程可以调用子线程的 join(),让主线程等待子线程执行完毕后再继续执行。

2.2 join() 的底层原理

join() 的执行流程如下:

  1. join() 被调用时,当前线程(例如主线程)会 等待目标线程执行完毕
  2. 当前线程会进入 等待状态,直到目标线程执行完毕,即线程的 isAlive() 返回 false
  3. 目标线程执行完毕后,join() 方法会返回,当前线程恢复执行。
javaCopy codeThread t1 = new Thread(() -> {
    // 子线程执行的操作
});

t1.start();
try {
    t1.join(); // 主线程等待 t1 完成
} catch (InterruptedException e) {
    e.printStackTrace();
}
// 主线程继续执行

2.3 join() 的实现

Thread.join() 的底层实现实际上使用了 wait()。具体而言,当一个线程调用 join() 时,当前线程会进入 等待状态,直到目标线程执行完毕时,join() 内部会通过 notify() 唤醒等待的线程。内部调用了线程对象的 wait() 来实现等待,直到目标线程结束。

2.4 关键点

  • join() 是一种用于控制线程执行顺序的方法,调用线程会等待目标线程执行完毕。
  • 它主要用于线程 结束 时的同步控制。
  • wait() 不同的是,join() 是线程级别的控制,而 wait()/notify() 是对象锁的控制。

3. Object.wait()Thread.join() 的主要区别

特性Object.wait()Thread.join()
功能用于线程间的协作与通信,线程等待条件变化用于等待某个线程执行结束
应用场景需要与 notify()notifyAll() 配合使用线程间的顺序控制,等待线程结束
调用方式必须在同步块中调用,并且需要持有对象的锁可以在任何地方调用,不需要同步块
是否释放锁调用后会释放锁,并等待其他线程唤醒不涉及锁的释放,仅等待目标线程结束
对象级别 or 线程级别对象级别,等待在对象锁上线程级别,等待线程执行完毕
底层机制调用线程进入 等待队列,直到被 notify() 唤醒当前线程进入 等待状态,直到目标线程结束

4. 使用场景对比

4.1 Object.wait() 适合的场景

wait() 适用于 生产者-消费者模型任务队列 等需要线程间通信的场景。

  • 例如,在生产者-消费者问题中,生产者线程在任务队列满时调用 wait(),消费者线程在任务队列空时调用 wait(),当条件满足后,双方通过 notify()notifyAll() 通信。

4.2 Thread.join() 适合的场景

join() 适用于 线程执行顺序控制。常见的使用场景是:

  • 主线程启动若干个子线程进行并行任务,主线程通过 join() 方法等待这些子线程执行完毕后,才进行最终的结果汇总或后续操作。

总结

  • Object.wait():用于线程间通信,等待某个条件的改变,常用于同步块中与 notify() 配合,涉及对象级别的锁控制。
  • Thread.join():用于线程的顺序控制,当前线程等待目标线程执行完毕后继续执行,常用于主线程与子线程的协调。

了解这两者的差异及其适用场景有助于编写更高效的多线程程序。在需要线程间通信时选择 wait()/notify(),而在需要控制线程执行顺序时选择 join()

0 0 投票数
Article Rating
订阅评论
提醒
guest
0 评论
最旧
最新 最多投票
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x