摘要:必须放在中,否则会在时扔出异常。为了控制线程执行的顺序,那么就必须要确定唤醒等待的顺序,所以每一个线程必须同时持有两个对象锁,才能继续执行。一个对象锁是,就是前一个线程所持有的对象锁。
简单介绍
wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。wiat()必须放在synchronized block中,否则会在program runtime时扔 出“java.lang.IllegalMonitorStateException”异常。 简单的介绍就到这里,现在我们用一个例子来深入理解一下
package com.example.demo.test.MultithreadingTest; public class MyThreadPrinter2 implements Runnable { private String name; private Object prev; private Object self; private MyThreadPrinter2(String name, Object prev, Object self) { this.name = name; this.prev = prev; this.self = self; } @Override public void run() { int count = 10; int x=0; while (count > 0) { synchronized (prev) { synchronized (self) { System.out.print(name); count--; x++; self.notify(); } try { prev.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (prev){ System.out.print(x); } } } public static void main(String[] args) throws Exception { Object a = new Object(); Object b = new Object(); Object c = new Object(); MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a); MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b); MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c); new Thread(pa).start(); Thread.sleep(100); new Thread(pb).start(); Thread.sleep(100); new Thread(pc).start(); Thread.sleep(100); } }
输出结果:
ABC1A1B1C2A2B2C3A3B3C4A4B4C5A5B5C6A6B6C7A7B7C8A8B8C9A9B9C10
这段代码为三线程间的同步唤醒操作,主要的目的就是ThreadA->ThreadB->ThreadC->ThreadA循环执行三个线程。
为了控制线程执行的顺序,那么就必须要确定唤醒、等待的顺序,所以每一个线程必须同时持有两个对象锁,才能继续执行。一个对象锁是prev,就是前一个线程所持有的对象锁。还有一个就是自身对象锁。主要的思想就是,为了控制执行的顺序,必须要先持有prev锁,也就前一个线程要释放自身对象锁,再去申请自身对象锁,两者兼备时打印,之后首先调用self.notify()释放自身对象锁,唤醒下一个等待线程,再调用prev.wait()释放prev对象锁,终止当前线程,等待循环结束后再次被唤醒。prev.wait()之后,加入了一个对象锁是prev的输出x,用来展示什么时候释放了prev对象锁。
运行上述代码,可以发现先打印出A,再释放A,然后C锁,进入ThreadB,打印出B,再释放B,然后A锁,进入ThreadC,打印出C,再释放C,然后B锁,此时会进入ThreadA,继续执行开始时wait的线程,输出x,打印出A,再释放A,然后C锁......如此循环
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/71618.html
摘要:和简介和均为的方法暂停一个线程唤醒一个线程从以上的定义中,我们可以了解到以下事实想要使用这两个方法,我们需要先有一个对象。在中任何一个时刻,对象的控制权只能被一个线程拥有。若有多个线程处于此控制权下的状态,只有一个会被唤醒。 最近看帖子,发现一道面试题: 启动两个线程, 一个输出 1,3,5,7…99, 另一个输出 2,4,6,8…100 最后 STDOUT 中按序输出 1,2,3,4...
摘要:无论在中出现什么,都可以认为它是对象除了八大基本数据类型。让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。但是要注意的是方法调用后,被唤醒的线程不会立马获得到锁对象。主要的区别在于在释放同时,释放了对象锁的控制。 前言 五一回家又断更了一个放假时间了~~~ 只有光头才能变强 回顾前面: ThreadLocal就是这么简单 多线程三分钟就可以入个门了! 多线程基础必要知识点!...
摘要:方法可以将当前线程放入等待集合中,并释放当前线程持有的锁。此后,该线程不会接收到的调度,并进入休眠状态。该线程会唤醒,并尝试恢复之前的状态。 并发 最近重新复习了一边并发的知识,发现自己之前对于并发的了解只是皮毛。这里总结以下Java并发需要掌握的点。 使用并发的一个重要原因是提高执行效率。由于I/O等情况阻塞,单个任务并不能充分利用CPU时间。所以在单处理器的机器上也应该使用并发。为...
摘要:运行可运行状态的线程获得了时间片,执行程序代码。阻塞的情况分三种一等待阻塞运行的线程执行方法,会把该线程放入等待队列中。死亡线程方法执行结束,或者因异常退出了方法,则该线程结束生命周期。死亡的线程不可再次复生。 系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键...
阅读 2862·2021-11-15 11:39
阅读 1495·2021-08-19 10:56
阅读 1074·2019-08-30 14:12
阅读 3669·2019-08-29 17:29
阅读 660·2019-08-29 16:21
阅读 3402·2019-08-26 12:22
阅读 1496·2019-08-23 16:30
阅读 991·2019-08-23 15:25