wait()和sleep()、yield()、jion()如何使用?
yuyutoo 2024-12-10 21:50 4 浏览 0 评论
wait()方法
- 定义和所属类:wait()方法是java.lang.Object类中的一个方法。这意味着在 Java 中,任何对象都可以调用这个方法。
- 作用机制:
- 当一个线程调用一个对象的wait()方法时,它会释放该对象的锁,然后进入等待状态。这个线程会一直等待,直到其他线程调用该对象的notify()或notifyAll()方法来唤醒它。例如,在一个生产者 - 消费者模型中,消费者线程在发现缓冲区为空时,可以调用wait()方法等待生产者生产数据。当生产者生产了数据并调用notify()方法后,消费者线程就会被唤醒,重新获取对象的锁并继续执行。
- 线程在wait()状态下是处于阻塞状态的一种,它会被放入对象的等待队列中,这个队列是和对象关联的,用于管理等待这个对象的线程。
- 使用场景:主要用于线程之间的协作和同步。比如在多线程访问共享资源(如共享数据结构)时,通过wait()和notify()可以实现对资源访问的有效控制,避免数据竞争和不一致性。
- 注意事项:调用wait()方法必须在同步代码块或者同步方法中,因为wait()方法会释放对象的锁,所以需要先获取锁才能释放。否则会抛出IllegalMonitorStateException异常。
- 示例代码:
import java.util.ArrayList;
import java.util.List;
class ProducerConsumerExample {
private List<Integer> buffer = new ArrayList<>();
private final int bufferSize = 5;
public synchronized void produce() {
while (buffer.size() == bufferSize) {
try {
// 如果缓冲区已满,生产者线程等待
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
buffer.add(1);
System.out.println("Produced. Buffer size: " + buffer.size());
// 通知消费者线程可以消费了
notify();
}
public synchronized void consume() {
while (buffer.isEmpty()) {
try {
// 如果缓冲区为空,消费者线程等待
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
buffer.remove(0);
System.out.println("Consumed. Buffer size: " + buffer.size());
// 通知生产者线程可以生产了
notify();
}
}
public class WaitExample {
public static void main(String[] args) {
ProducerConsumerExample example = new ProducerConsumerExample();
Thread producerThread = new Thread(example::produce);
Thread consumerThread = new Thread(example::consume);
producerThread.start();
consumerThread.start();
}
}
在上述代码中,生产者线程在缓冲区已满时调用wait()方法等待,消费者线程在缓冲区为空时也调用wait()方法等待。当生产者生产了一个数据后,通过notify()方法通知消费者线程,当消费者消费了一个数据后,通过notify()方法通知生产者线程。
sleep()方法
- 定义和所属类:sleep()方法是java.lang.Thread类中的一个静态方法。这意味着它是通过线程类来调用的,而不是像wait()那样通过对象来调用。
- 作用机制:
- 当一个线程调用Thread.sleep(long millis)方法时,它会使当前线程暂停执行指定的毫秒数。在这个期间,线程进入阻塞状态,但和wait()不同的是,它不会释放对象的锁(如果线程持有锁的话)。例如,如果一个线程在同步方法中调用sleep()方法,它依然会持有该方法所属对象的锁,其他线程无法访问这个同步方法,直到sleep()时间结束。
- 线程在sleep()结束后,会重新进入就绪状态,等待 CPU 调度,然后继续执行。
- 使用场景:用于让线程暂停一段时间,比如模拟延迟、定时任务等。例如,一个每隔一段时间就检查系统状态的线程,可以通过sleep()方法来实现定时检查。
- 注意事项:sleep()方法可能会抛出InterruptedException异常。这个异常通常在其他线程调用当前线程的interrupt()方法时抛出。所以在调用sleep()方法时,通常需要在try - catch块中处理这个异常。
- 示例代码:
public class SleepExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
System.out.println("Thread started.");
// 线程暂停 3 秒
Thread.sleep(3000);
System.out.println("Thread resumed after 3 seconds.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
thread.start();
}
}
在这个例子中,创建了一个线程,该线程在启动后先打印一条消息,然后调用sleep(3000)让线程暂停 3 秒,3 秒后继续执行并打印另一条消息。
yield()方法
- 定义和所属类:yield()方法是java.lang.Thread类中的一个静态方法。
- 作用机制:
- 当一个线程调用yield()方法时,它是在暗示调度器自己当前可以让出 CPU 资源。但是调度器是否会真正让当前线程暂停执行,这是不确定的。它可能会让当前线程暂停,然后重新进入就绪队列,等待下一次调度;也可能会忽略这个请求,让线程继续执行。
- 线程调用yield()方法后,会从运行状态转换到就绪状态,它不会像sleep()那样进入阻塞状态,也不会释放对象的锁(如果线程持有锁的话)。
- 使用场景:用于在多线程环境中,当一个线程完成了一部分任务,并且认为其他线程可能更需要 CPU 资源时,可以调用yield()方法来给其他线程机会执行。不过由于调度器的不确定性,它在实际应用中的效果可能不太好预测。
- 注意事项:yield()方法是一种启发式的方法,不能保证一定能达到预期的调度效果。在不同的操作系统和 JVM 实现中,yield()方法的行为可能会有所不同。
- 示例代码:
public class YieldExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread 1: " + i);
// 偶尔让出 CPU 资源
if (i % 2 == 0) {
Thread.yield();
}
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread 2: " + i);
// 偶尔让出 CPU 资源
if (i % 3 == 0) {
Thread.yield();
}
}
});
thread1.start();
thread2.start();
}
}
在这个例子中,创建了两个线程,它们在循环中偶尔调用yield()方法尝试让出 CPU 资源,但实际效果取决于调度器的决策。
join()方法
- 定义和所属类:join()方法是java.lang.Thread类中的一个方法。
- 作用机制:
- 当在一个线程中调用另一个线程的join()方法时,当前线程会被阻塞,直到被调用join()方法的线程执行完毕。例如,有线程 A 和线程 B,在 A 中调用 B.join (),那么 A 会暂停执行,等待 B 完成后 A 才会继续执行。
- 使用场景:用于协调线程的执行顺序。比如在主线程中,如果需要等待某个子线程完成特定任务后再继续执行后续操作,就可以使用join()方法。
- 注意事项:join()方法可能会抛出InterruptedException异常。这个异常通常在当前线程被中断时抛出。所以在调用join()方法时,通常也需要在try - catch块中处理这个异常。
- 示例代码:
public class JoinExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
System.out.println("Sub - thread started.");
// 模拟子线程执行一些耗时任务
Thread.sleep(2000);
System.out.println("Sub - thread finished.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
thread.start();
try {
System.out.println("Main thread is waiting for sub - thread to finish.");
// 主线程等待子线程完成
thread.join();
System.out.println("Main thread continues after sub - thread finished.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
在这个例子中,主线程启动一个子线程后,调用join()方法等待子线程完成。子线程在执行过程中会暂停 2 秒来模拟耗时任务,当子线程完成后,主线程才会继续执行。
异同点总结
- 相同点:
- 状态转换:wait()、sleep()、yield()和join()方法都会导致线程状态的改变。wait()和sleep()方法会使线程进入阻塞状态(wait()是无限等待或等待被唤醒,sleep()是限时等待),yield()方法会使线程从运行状态转换到就绪状态,join()方法会使当前线程进入阻塞状态,直到被调用join()方法的线程执行完毕。
- 影响执行顺序:它们都在一定程度上影响了线程的执行顺序。wait()是等待其他线程唤醒,sleep()是暂停一段时间后再继续执行,yield()是让出 CPU 资源(可能),join()是等待另一个线程完成,这些操作都会改变线程原本的执行顺序。
- 不同点:
- 所属类和调用方式:wait()是Object类的方法,需要通过对象来调用;sleep()和yield()、join()是Thread类的方法,sleep()和join()是实例方法,yield()是静态方法,sleep()是通过Thread.sleep()调用,yield()是通过Thread.yield()调用,join()是通过线程对象的join()方法调用。
- 锁的释放:wait()方法会释放对象的锁,而sleep()、yield()和join()方法不会释放对象的锁(如果线程持有锁的话)。
- 等待性质:wait()是等待其他线程通过notify()或notifyAll()来唤醒,是一种基于对象通知的等待;sleep()是基于时间的等待,线程会在指定时间后自动恢复;yield()是一种协作式的让出 CPU 资源,调度器是否接受这个请求是不确定的;join()是等待指定线程执行完毕的等待。
相关推荐
- 全局和隐式 using 指令详解(全局命令)
-
1.什么是全局和隐式using?在.NET6及更高版本中,Microsoft引入了...
- 请停止微服务,做好单体的模块化才是王道:Spring Modulith介绍
-
1、介绍模块化单体是一种架构风格,代码是根据模块的概念构成的。对于许多组织而言,模块化单体可能是一个很好的选择。它有助于保持一定程度的独立性,这有助于我们在需要的时候轻松过渡到微服务架构。Spri...
- ASP.NET程序集引用之痛:版本冲突、依赖地狱等解析与实战
-
我是一位多年后端经验的工程师,其中前几年用ASP.NET...
- .NET AOT 详解(.net 6 aot)
-
简介AOT(Ahead-Of-TimeCompilation)是一种将代码直接编译为机器码的技术,与传统的...
- 一款基于Yii2开发的免费商城系统(一款基于yii2开发的免费商城系统是什么)
-
哈喽,我是老鱼,一名致力于在技术道路上的终身学习者、实践者、分享者!...
- asar归档解包(游戏arc文件解包)
-
要学习Electron逆向,首先要有一个Electron开发的程序的发布的包,这里就以其官方的electron-quick-start作为例子来进行一下逆向的过程。...
- 在PyCharm 中免费集成Amazon CodeWhisperer
-
CodeWhisperer是Amazon发布的一款免费的AI编程辅助小工具,可在你的集成开发环境(IDE)中生成实时单行或全函数代码建议,帮助你快速构建软件。简单来说,AmazonCodeWhi...
- 2014年最优秀JavaScript编辑器大盘点
-
1.WebstormWebStorm是一种轻量级的、功能强大的IDE,为Node.js复杂的客户端开发和服务器端开发提供完美的解决方案。WebStorm的智能代码编辑器支持JavaScript,...
- 基于springboot、tio、oauth2.0前端vuede 超轻量级聊天软件分享
-
项目简介:基于JS的超轻量级聊天软件。前端:vue、iview、electron实现的PC桌面版聊天程序,主要适用于私有云项目内部聊天,企业内部管理通讯等功能,主要通讯协议websocket。支持...
- JetBrains Toolbox推出全新产品订阅授权模式
-
捷克知名软件开发公司JetBrains最为人所熟知的产品是Java编程语言开发撰写时所用的集成开发环境IntelliJIDEA,相信很多开发者都有所了解。而近期自2015年11月2日起,JetBr...
- idea最新激活jetbrains-agent.jar包,亲测有效
-
这里分享一个2019.3.3版本的jetbrains-agent.jar,亲测有效,在网上找了很多都不能使用,终于找到一个可以使用的了,这里分享一下具体激活步骤,此方法适用于Jebrains家所有产品...
- CountDownTimer的理解(countdowntomars)
-
CountDownTimer是android开发常用的计时类,按照注释中的说明使用方法如下:kotlin:object:CountDownTimer(30000,1000){...
- 反射为什么性能会很慢?(反射时为什么会越来越长)
-
1.背景前段时间维护一个5、6年前的项目,项目总是在某些功能使用上不尽人意,性能上总是差一些,仔细过了一下代码发现使用了不少封装好的工具类,工具类里面用了好多的反射,反射会影响到执行效率吗?盲猜了一...
- btrace 开源!基于 Systrace 高性能 Trace 工具
-
介绍btrace(又名RheaTrace)是抖音基础技术团队自研的一款高性能AndroidTrace工具,它基于Systrace实现,并针对Systrace不足之处加以改进,核心改进...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- .NET 奇葩问题调试经历之3——使用了grpc通讯类库后,内存一直增长......
- 全局和隐式 using 指令详解(全局命令)
- 请停止微服务,做好单体的模块化才是王道:Spring Modulith介绍
- ASP.NET程序集引用之痛:版本冲突、依赖地狱等解析与实战
- .NET AOT 详解(.net 6 aot)
- 一款基于Yii2开发的免费商城系统(一款基于yii2开发的免费商城系统是什么)
- asar归档解包(游戏arc文件解包)
- 在PyCharm 中免费集成Amazon CodeWhisperer
- 2014年最优秀JavaScript编辑器大盘点
- 基于springboot、tio、oauth2.0前端vuede 超轻量级聊天软件分享
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)