Java多线程的wait(),notify(),notifyAll()、sl…
2020-03-18 16:01:29来源:博客园 阅读 ()
Java多线程的wait(),notify(),notifyAll()、sleep()和yield()方法使用详解
Java多线程的wait(),notify(),notifyAll()、sleep()和yield()方法使用详解Java多线程中的wait(),notify(),notifyAll()、sleep()和yield()方法
我们先从一个案例开始:
static public class WaitingTest {
//static创建静态对象,确保是同一个monitor对象
static Object obj = new Object();
public static void main(String[] args) {
//new Thread(Runnable target, String name)
//第一个线程,匿名内部类形式创建,name:"等待线程"
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
synchronized (obj) {
System.out.println(Thread.currentThread().getName()+
"===>获取到锁对象,调用wait方法,进入waiting状态,释放锁对象");
try {
obj.wait(); //无限等待,如果想唤醒一个正在等待的线程,那么需要开启一个线程通过notify()或者notifyAll()方法去通知正在等待的线程获取monitor对象。notify()唤醒一个wait对象,或者notifyAll唤醒所有wait对象。
} catch (InterruptedException e) {
e.printStackTrace();
}
//若没有notify()唤醒,则下面这句话永远不执行
System.out.println(Thread.currentThread().getName()+
"=====>从waiting状态醒来,获得了锁对象,可以继续执行了...");
}
}
}
},"等待线程").start();
//第二个线程,同样也是匿名内部类形式创建,name:"唤醒线程"
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
System.out.println(Thread.currentThread().getName()+"=====>休眠三秒钟");
try {
Thread.sleep(3000L);//虽然当前线程进入了睡眠状态,但是依然持有monitor对象。在中断完成之后,自动进入唤醒状态从而继续执行代码
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
System.out.println(Thread.currentThread().getName()+
"=====>获得了锁对象,调用notify方法,释放锁对象");
obj.notify();
}
}
}
},"唤醒线程").start();
}
}
执行结果:
? 等待线程===>获取到锁对象,调用wait方法,进入waiting状态,释放锁对象
? 唤醒线程=====>休眠三秒钟
? 唤醒线程=====>获得了锁对象,调用notify方法,释放锁对象
? 唤醒线程=====>休眠三秒钟
? 等待线程=====>从waiting状态醒来,获得了锁对象,可以继续执行了...
? 等待线程===>获取到锁对象,调用wait方法,进入waiting状态,释放锁对象
? 唤醒线程=====>获得了锁对象,调用notify方法,释放锁对象
? 唤醒线程=====>休眠三秒钟
? 等待线程=====>从waiting状态醒来,获得了锁对象,可以继续执行了...
? 等待线程===>获取到锁对象,调用wait方法,进入waiting状态,释放锁对象
wait()方法:
(1)调用了wait()之后当前线程会处于等待状态(无限等待状态)。
(2)每个线程必须持有该对象的monitor(Object's monitor)。如果在当前线程中调用wait()方法之后,该线程就会释放monitor的持有对象并让自己处于等待状态。
(3)如果想唤醒一个正在等待的线程,那么需要开启一个线程通过notify()或者notifyAll()方法去通知正在等待的线程获取monitor对象。当然,需要注意的一点就是,必须是同一个monitor对象。如此,该线程即可打破等待的状态继续执行代码。
notify()方法:
(1)当一个线程处于wait()状态时,也即等待它之前所持有的object's monitor被释放,通过notify()方法可以让该线程重新处于活动状态,从而去抢夺object's monitor,唤醒该线程。
(2)如果多个线程同时处于等待状态,那么调用notify()方法只能随机唤醒一个线程。
(3)在同一时间内,只有一个线程能够获得object's monitor,执行完毕之后,则再将其释放供其它线程抢占。
notifyAll()方法:
(1)notifyAll()只会唤醒那些等待抢占指定object's monitor的线程,其他线程则不会被唤醒。
(2)notifyAll()只会一个一个的唤醒,而并非统一唤醒。因为在同一时间内,只有一个线程能够持有object's monitor
(3)notifyAll()只是随机的唤醒线程,并非有序唤醒。
总结:
? wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对像都有wait(),notify(),notifyAll()的功能。因为都个对像都有锁,锁是每个对像的基础,当然操作锁的方法也是最基础了。
sleep()方法:sleep(long millis) sleep(long millis, int nanos)
(1)调用sleep()之后,会引起当前执行的线程进入暂时中断状态,睡眠状态,即阻塞状态。
(2)虽然当前线程进入了阻塞状态,但是依然持有monitor对象。
(3)在中断完成之后,自动进入就绪状态。sleep()方法虽然会使线程中断,但是不会将自己的monitor对象释放,在中断结束后,依然能够保持代码继续执行。
yield()方法:线程让步
(1)使线程从运行状态到就绪状态,所以yield()方法很有可能刚执行完又继续获取到CPU资源继续执行。
(2)调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程,即让系统线程调度器重新调度。
(3)它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间(没有形参)。
(4)yield()只会让同优先级或更高优先级得到执行机会,而sleep()是无限制的。
最后附一张我自己的手绘多线程生命周期图(字有点丑,请见谅)
如有错误,欢迎指点
原文链接:https://www.cnblogs.com/yZzcXQ/p/JavaSE-thread.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:java 内部类
- 国外程序员整理的Java资源大全(全部是干货) 2020-06-12
- 2020年深圳中国平安各部门Java中级面试真题合集(附答案) 2020-06-11
- 2020年java就业前景 2020-06-11
- 04.Java基础语法 2020-06-11
- Java--反射(框架设计的灵魂)案例 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash