Java基础——Java多线程中sleep()、wait()和notify()
一、sleep()
sleep()方法源码:
/** * Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds, subject to * the precision and accuracy of system timers and schedulers. The thread * does not lose ownership of any monitors. * * @param millis * the length of time to sleep in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ public static native void sleep(long millis) throws InterruptedException;
sleep()方法来自于Thread类,从源码给出的解释来看,sleep()方法可以做到如下几点:
(1)sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会;
(2)sleep()是Thread类的Static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用Sleep()方法时,线程虽然休眠了,但是对象的机锁并木有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。
(3)在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。
代码演示:
public class Main { public static void main(String[] args) { Main main = new Main(); main.startThread(); } /** * 启动线程 */ public void startThread() { Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("开始执行线程。。。"); System.out.println("进入睡眠状态。。。"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程结束。。。"); } }); t.start(); }
}
运行结果:
开始执行线程。。。
进入睡眠状态。。。
线程结束。。。
从运行的结果来看,我们可以看出程序虽然在运行过程中中断了3秒,但是在3秒结束之后依然会继续执行代码,直到运行结束。在睡眠的期间内,线程会一直持有monitor对象。
二、wait()
wait()方法源码:
/** * Causes the current thread to wait until another thread invokes the * {@link java.lang.Object#notify()} method or the * {@link java.lang.Object#notifyAll()} method for this object. * In other words, this method behaves exactly as if it simply * performs the call {@code wait(0)}. * <p> * The current thread must own this object's monitor. The thread * releases ownership of this monitor and waits until another thread * notifies threads waiting on this object's monitor to wake up * either through a call to the {@code notify} method or the * {@code notifyAll} method. The thread then waits until it can * re-obtain ownership of the monitor and resumes execution. * <p> * As in the one argument version, interrupts and spurious wakeups are * possible, and this method should always be used in a loop: * <pre> * synchronized (obj) { * while (<condition does not hold>) * obj.wait(); * ... // Perform action appropriate to condition * } * </pre> * This method should only be called by a thread that is the owner * of this object's monitor. See the {@code notify} method for a * description of the ways in which a thread can become the owner of * a monitor. * * @exception IllegalMonitorStateException if the current thread is not * the owner of the object's monitor. * @exception InterruptedException if any thread interrupted the * current thread before or while the current thread * was waiting for a notification. The <i>interrupted * status</i> of the current thread is cleared when * this exception is thrown. * @see java.lang.Object#notify() * @see java.lang.Object#notifyAll() */ public final void wait() throws InterruptedException { wait(0); }
首先wait()是属于Object类的方法,从源码给出的解释来看,wait()方法可以做到如下几点:
(1)wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;
(2)每个线程必须持有该对象的monitor。如果在当前线程中调用wait()方法之后,该线程就会释放monitor的持有对象并让自己处于等待状态。
(3)如果想唤醒一个正在等待的线程,那么需要开启一个线程通过notify()或者notifyAll()方法去通知正在等待的线程获取monitor对象。如此,该线程即可打破等待的状态继续执行代码。
(4)wiat()必须放在synchronized block中,否则会在program runtime时扔出”java.lang.IllegalMonitorStateException“异常。
代码演示:
public class Main { public static void main(String[] args) { Main main = new Main(); main.startThread(); } /** * 线程锁 */ private final Object object = new Object(); /** * 启动线程 */ public void startThread() { Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("开始执行线程。。。"); System.out.println("进入等待状态。。。"); synchronized (object) { try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("线程结束。。。"); } }); t.start(); }
}
从代码来看,在执行线程和线程结束之间,我们先让该线程获取object对象作为自己的object's monitor,然后调用了object对象的wait()方法从而让其进入等待状态。那么程序运行的结果如下:
开始执行线程。。。
进入等待状态。。。
程序在未被唤醒之后,将不再打印“线程结束”,并且程序无法执行完毕一直处于等待状态。
那么从以上的理论和实践来分析,我们能得出如下结论:
(1)在线程的运行过程中,调用该线程持有monitor对象的wait()方法时,该线程首先会进入等待状态,并将自己持有的monitor对象释放。
(2)如果一个线程正处于等待状态时,那么唤醒它的办法就是开启一个新的线程,通过notify()或者notifyAll()的方式去唤醒。当然,需要注意的一点就是,必须是同一个monitor对象。
(3)sleep()方法虽然会使线程中断,但是不会将自己的monitor对象释放,在中断结束后,依然能够保持代码继续执行。
三、notify()和notifyAll()
说完了sleep()和wait()方法之后,我们接下来讨论一下Object类中的另外两个与wait()相关的方法。首先还是通过源码的方式让大家先初步了解一下:
/** * Wakes up a single thread that is waiting on this object's * monitor. If any threads are waiting on this object, one of them * is chosen to be awakened. The choice is arbitrary and occurs at * the discretion of the implementation. A thread waits on an object's * monitor by calling one of the {@code wait} methods. * <p> * The awakened thread will not be able to proceed until the current * thread relinquishes the lock on this object. The awakened thread will * compete in the usual manner with any other threads that might be * actively competing to synchronize on this object; for example, the * awakened thread enjoys no reliable privilege or disadvantage in being * the next thread to lock this object. * <p> * This method should only be called by a thread that is the owner * of this object's monitor. A thread becomes the owner of the * object's monitor in one of three ways: * <ul> * <li>By executing a synchronized instance method of that object. * <li>By executing the body of a {@code synchronized} statement * that synchronizes on the object. * <li>For objects of type {@code Class,} by executing a * synchronized static method of that class. * </ul> * <p> * Only one thread at a time can own an object's monitor. * * @exception IllegalMonitorStateException if the current thread is not * the owner of this object's monitor. * @see java.lang.Object#notifyAll() * @see java.lang.Object#wait() */ public final native void notify();
/** * Wakes up all threads that are waiting on this object's monitor. A * thread waits on an object's monitor by calling one of the * {@code wait} methods. * <p> * The awakened threads will not be able to proceed until the current * thread relinquishes the lock on this object. The awakened threads * will compete in the usual manner with any other threads that might * be actively competing to synchronize on this object; for example, * the awakened threads enjoy no reliable privilege or disadvantage in * being the next thread to lock this object. * <p> * This method should only be called by a thread that is the owner * of this object's monitor. See the {@code notify} method for a * description of the ways in which a thread can become the owner of * a monitor. * * @exception IllegalMonitorStateException if the current thread is not * the owner of this object's monitor. * @see java.lang.Object#notify() * @see java.lang.Object#wait() */ public final native void notifyAll();
notify()实现有序唤醒的思路和实现
public class MyThreadFactory { // 线程A是否处于等待状态的标志 private boolean isThreadAWaiting; // 线程B是否处于等待状态的标志 private boolean isThreadBWaiting; // 线程C是否处于等待状态的标志 private boolean isThreadCWaiting; public MyThreadFactory() { isThreadAWaiting = true; isThreadBWaiting = true; isThreadCWaiting = true; } /** * 对象锁 */ private final Object object = new Object(); /** * 该线程作为一个唤醒线程 */ public void startWakenThread() { Thread t = new Thread(new Runnable() { @Override public void run() { synchronized (object) { System.out.println("唤醒线程开始执行..."); // 首先释放线程A quitThreadA(); } } }); t.start(); } /** * 启动线程A */ public void startThreadA() { Thread t = new Thread(new Runnable() { @Override public void run() { synchronized (object) { System.out.println("线程A开始等待..."); try { for (; ; ) { if (!isThreadAWaiting) break; object.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程A结束..."); // 线程A结束后,暂停2秒释放线程B try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } quitThreadB(); } } }); t.start(); } /** * 启动线程B */ public void startThreadB() { Thread t = new Thread(new Runnable() { @Override public void run() { synchronized (object) { System.out.println("线程B开始等待..."); try { for (; ; ) { if (!isThreadBWaiting) break; object.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程B结束..."); // 线程B结束后,暂停2秒释放线程C try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } quitThreadC(); } } }); t.start(); } /** * 启动线程C */ public void startThreadC() { Thread t = new Thread(new Runnable() { @Override public void run() { synchronized (object) { System.out.println("线程C开始等待..."); try { for (; ; ) { if (!isThreadCWaiting) break; object.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程C结束..."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("所有线程执行完毕!"); } } }); t.start(); } /** * 线程A退出等待 */ private void quitThreadA() { isThreadAWaiting = false; object.notify(); } /** * 线程B退出等待 */ private void quitThreadB() { isThreadBWaiting = false; object.notify(); } /** * 线程C退出等待 */ private void quitThreadC() { isThreadCWaiting = false; object.notify(); }
}
public static void main(String[] args) { MyThreadFactory factory = new MyThreadFactory(); factory.startThreadA(); factory.startThreadB(); factory.startThreadC(); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } factory.startWakenThread(); }
运行结果:
线程A开始等待...
线程B开始等待...
线程C开始等待...
唤醒线程开始执行...
线程A结束...
线程B结束...
线程C结束...
所有线程执行完毕...
Java基础——Java多线程中sleep()、wait()和notify()相关推荐
- java wait notifyall_Java多线程中的wait与notify,notifyall例子
文章来给各位介绍一下Java多线程中的wait与notify,notifyall例子,希望文章能给各位朋友带来帮助哦. 在Java多线程编程中,wait()的作用的是让当前线程进入阻塞状态,notif ...
- Java基础、多线程、JVM、集合八股文自述(持续更新)
Java基础.多线程.JVM.集合八股文自述 一.Java基础 1.1 object类有哪些方法? getClass().hashCode().equals().clone().toString(). ...
- Java基础-Java中常用的锁机制与使用
Java基础-Java中常用的锁机制与使用 锁lock或互斥mutex是一种同步机制,主要用于在存在多线程的环境中强制对资源进行访问限制.锁的主要作用为强制实施互斥排他以及并发控制策略.锁一般需要硬件 ...
- Java基础-Java中的堆内存和离堆内存机制
Java基础-Java中的堆内存和离堆内存机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 转载于:https://www.cnblogs.com/yinzhengjie/p/9 ...
- Java基础-JAVA中常见的数据结构介绍
Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...
- Java基础-Java中的内存分配与回收机制
Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二. 转载于:https://www.cnblogs.com/yinzhengji ...
- Java基础之Java8中Map的compute的使用
Java基础之Java8中Map的compute的使用 一.介绍 Java8更新后,Map接口中提供了compute方法.下面我们先看看官方文档的对它的使用说明. 如果看完上面的还是不太明白的话,看下 ...
- [重学Java基础][Java IO流][Exter.2]IO流中几种不同的读写方法的区别
[重学Java基础][Java IO流][Exter.2]IO流中几种不同的读写方法的区别 Read 读入方法 read(): 一般是这种形式 public int read() 1.从流数据中读取的 ...
- Java基础之Java8中map和flatMap的使用
Java基础之Java8中map和flatMap的使用 一.介绍 首先,看下map和flatMap的官方文档说明 map flatMap 其实单纯的看api说明还是比较抽象,下面我将以几个实战例子来帮 ...
- Java基础----Java编程语言概述
Java基础----Java编程语言概述 文章目录 Java基础----Java编程语言概述 Java编程语言概述 1-1 软件开发介绍 1.1软件开发介绍 1.2 常用命令 1-2 计算机编程语言介 ...
最新文章
- 用于自动驾驶的实时 YUV 多任务 CNN
- .NET架构与模式探索
- Cissp-【第2章 资产安全】-2021-1-14(163页-185页)
- 20165218 2017-2018-1 《Java程序设计》第四周学习总结
- Mac下PyCharm CE 配置PyQt5环境
- eclipse下的tomcat内存设置大小
- 日常生活收缩毛孔几个小妙招 - 健康程序员,至尚生活!
- 虚拟服务器 端口管理,Apache服务配置虚拟主机(基于域名、端口、IP地址)与简单访问权限管理...
- linux yum选择版本mysql_linux yum安装指定版本mysql
- 执行nvidia-smi出错
- arduino怎么和C语言程序通信,c – 如何将arduino库与标准C代码一起使用
- LINUX C# 加载本地库的范例代码
- 快手用户群体分析_抖音、快手竞品分析报告
- mysql2000数据库四合一_sql2000四合一版下载|microsoft sql server2000 简体中文4合一版附sql 2000 sp4 补丁_ - 极光下载站...
- [python-opencv]滑动验证码打码
- 国产免费倾斜摄影模型在线发布平台,一键查看、编辑、分享场景!
- BZOJ1022 [SHOI2008]小约翰的游戏John
- es的DSL语句查询
- 基于vspd DLL二次开发的虚拟串口工具
- 达梦物化视图概念及简单示例
热门文章
- mysql replace first_Java replaceFirst()方法
- 敏捷开发流程的8个步骤_敏捷开发——个体和互动高于流程和工具
- LSGO软件技术团队与信息1402班开展真人CS活动
- C#中 ??、 ?、 ?: 、?.、?[ ]、:
- ajax中怎么验证data,我应该在jQuery的ajax成功处理程序中验证响应数据吗?
- python @修饰符_python函数修饰符@的使用方法解析
- 解决:VS中进行Qt开发,编译时报错:打不开QWidgets.h等文件的问题
- REVERSE-PRACTICE-JarvisOJ-4
- 【POJ - 1741】Tree(树分治,容斥,点分治,模板题)
- 【牛客 - 330C】Applese 走迷宫(bfs)