大家好,本博客致力于分享互联网领域的各种技术干货,欢迎关注我们一起交流一起学习哦!
大家好,本博客致力于分享互联网领域的各种技术干货,欢迎关注我们一起交流一起学习哦!
在Java的多线程编程中,线程调度与控制是核心内容之一。
在多线程环境下,多个线程可能同时竞争CPU资源或共享数据。这就引出了几个关键问题:
某个时间段暂停,避免过度占用资源?资源冲突?获得通知并继续执行?为了解决这些问题,Java提供了诸如sleep()、wait()、notify()等线程控制机制。本文将分析这些方法如何更好地管理线程的执行顺序、资源锁定和释放等复杂问题。
sleep():暂停线程,不释放锁
sleep() 方法用于让当前线程进入阻塞状态,暂停执行一段时间。它的主要特点如下:
InterruptedException异常。Thread.sleep(2000); // 暂停当前线程2秒
使用场景:需要让线程暂停一段时间以降低资源占用时使用,但要注意它不释放锁,可能阻塞其他线程的执行。
wait():进入等待状态,并释放锁
wait() 会让线程进入等待状态,并且释放它持有的锁。它只能在synchronized块或方法中使用,且必须与notify()或notifyAll()配合使用来唤醒线程。
wait()和sleep()的最大区别是它会释放锁,让其他线程可以继续执行。notify()或notifyAll(),或者设定的超时时间到达,线程才会被唤醒。synchronized (lock) {
lock.wait(); // 当前线程进入等待状态,并释放锁
}
notify() 和 notifyAll():唤醒等待中的线程
notify() 和 notifyAll() 用来唤醒处于wait()状态的线程。
notify() 只随机唤醒一个等待该锁的线程。notifyAll() 会唤醒所有等待该锁的线程,随后这些线程将继续争抢锁。synchronized (lock) {
lock.notify(); // 唤醒一个等待的线程
}
使用场景:当需要通知一个或多个线程可以继续执行时使用,常与wait()配合使用。
yield():让出CPU资源,不释放锁
yield() 使当前线程主动让出CPU资源,让系统调度其他线程执行。但它并不释放持有的锁,因此其他线程仍然无法访问同步块中的共享资源。
使用场景:在多线程环境下,yield() 可以用于让当前线程暂时放弃CPU资源,给其他线程执行机会,常用于性能调优场景。
join():等待其他线程结束
join() 用于让当前线程等待另一个线程执行完毕后再继续执行。如果线程A调用了线程B的join()方法,那么A将进入阻塞状态,直到线程B执行完毕。
t.join(); // 当前线程等待t线程结束
join方法原理:
// 这是一个同步方法,主线程(调用线程)必须获取当前线程t的对象锁
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis(); // 记录开始时间
long now = 0; // 用于计算当前时间与基准时间的差
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
// 如果不传超时时间 (millis = 0),主线程将一直等待目标线程t完成
while (isAlive()) {
// 检查当前线程t是否还活着 (isAlive()返回true时表示线程还在执行)
// 进入等待,主线程(如main线程)进入阻塞状态并释放锁,直到目标线程t结束
wait(0);
// wait(0)表示无限期等待,直到目标线程t调用notifyAll()
}
} else {
// 如果传入了超时时间
while (isAlive()) {
// 持续检查目标线程t是否存活
long delay = millis - now; // 计算剩余的等待时间
if (delay <= 0) {
break; // 超时时间到了,跳出循环,不再等待
}
// 主线程等待指定时间,直到目标线程t结束或超时时间到
wait(delay);
now = System.currentTimeMillis() - base; // 更新已过去的时间
}
}
}
使用场景:常用于需要确保一个线程执行完后,才能执行下一个任务的场景。
关键区别与总结
通过以上分析,可以总结出这些方法的主要区别与应用场景:
| 方法 | 是否释放锁 | 是否释放CPU | 进入状态 | 唤醒方式 | 使用场景 |
|---|---|---|---|---|---|
sleep() |
否 | 是 | 阻塞状态 | 自动/被中断 | 暂停执行 |
wait() |
是 | 是 | 等待状态 |
notify()/notifyAll()
|
条件等待 |
notify() |
N/A | N/A | N/A | 唤醒一个等待线程 | 通知等待线程 |
notifyAll() |
N/A | N/A | N/A | 唤醒所有等待线程 | 通知所有等待线程 |
yield() |
否 | 是 | 就绪状态 | 系统调度 | 让出CPU资源 |
join() |
N/A | 是 | 阻塞状态 | 等待线程结束 | 线程协作 |
Java中的线程控制方法提供了多种灵活的机制,用于管理线程的执行顺序、资源占用和同步问题。sleep()和wait()分别用于让线程暂停或等待,其中wait()释放锁更适合同步场景,而sleep()适用于简单的暂停需求。yield()和join()则更多用于线程之间的协作与调度控制。最后,notify()和notifyAll()则是wait()的配套通知机制。
理解并正确使用这些方法是编写高效、多线程程序的关键。根据实际需求选择合适的线程控制方法,可以有效提升程序的执行效率与可靠性。
原文作者:服务端技术栈;如有侵权,请联系管理员删除。