《Java高并发编程详解-多线程架构与设计》线程间的通信
文章目录
同步、异步、阻塞、非阻塞概念
同步和异步
结果的通知机制。自己问还是别人通知。
同步:主动等待结果的返回。如阻塞等待,轮询(同步非阻塞)。
异步:被动等待结果的返回。如 消息回调。
阻塞和非阻塞
结果返回以前,调用方的状态。等还是不等。
阻塞:结果返回以前,什么也不干。
非阻塞:在结果返回以前,可以先做一些其他事情。
Monitor锁
下面所说的获取monitor锁都是指的先使用synchronized获取对象锁
不应该叫synchronized(mutex)为锁,而应该是某个线程获取了与mutex关联的monitor锁。
wait 与 notify
wait 理解成线程在等待直到该对象可用。(被notify后就不再等待)
notify理解成线程通知该对象可用。
使用wait的注意事项
-
wait必须在同步方法中使用,因为wait必须由拥有monitor(已用synchronize获取锁)的线程调用。
-
wait可以被中断,为了防止wait被interrupt唤醒,wait方法需要在循环中使用。
-
使用wait后自动释放线程对应的锁。–release ownership of this monitor
-
wait会等待直到其他线程调用notify/notifyAll唤醒。–waits until anthoer thread notifies threads waiting on this object’s monitor to wake up…
-
被notify/notifyAll唤醒后会重新获得锁的拥有权,然后接着执行。–re-obtain ownership of the monitor and resumes execution.
-
线程调用wait后, 会加入与之对应的wait set.每个对象都有一个与之对应的wait set.使用notify会将其中一个弹出,notifyAll弹出所有线程。(C5.3.2)
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)}.
*
* 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.
* As in the one argument version, interrupts and spurious wakeups are
* possible, and this method should always be used in a loop:
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait();
* … // Perform action appropriate to condition
* }
* 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.
使用notify的注意
-
必须在同步方法中使用wait、notify,因为他们的使用前提都是持有monitor所有权。
-
同步代码块的monitor必须与执行 wait 、notify的对象一致,也就是说对哪个对象同步,才能调用那个对象的 wait、notify。
例子:
若不是用的notifyAll, 则不能用于多线程环境
在while而不是if中调用wait!否则一旦被interrupt,会跳过判断继续执行。如
测试主动interrupt对if中使用wait的影响
这里主动interrupt,可见当producer被interrupt后,producer就略过了判断,继续添加了一个event
wait与sleep的
- 相同:
使线程阻塞
可以中断 - 不同:
wait是Object的方法,sleep是Thread的
wait必须要在同步代码块中执行。
wait会释放monitor的锁,sleep不会
sleep短暂休眠后会退出阻塞?(TODO)wait(没有指定时间的话)必须被中断才会退出阻塞。
synchronized的缺点
-
无法中断
synchronized不像sleep和wait那样,可以被中断。 -
没有等待时间
其他线程获取锁的拥有权必须要等待锁的拥有者(线程)释放后才能执行。
利用wait、notify实现可中断的BooleanLock
p96-104
一旦从wait中被唤醒则有机会检查lock是否为false,为false则修改获取锁的线程cureentLockThread为自己,并设置lock为true.防止其他线程继续争抢。
如果wait超时会报错,notify后超时 也主动抛错。
关键代码
从wait中被notify或者等待超时后,会因为while(locked),locked为false,说明没有线程持有monitor的拥有权,因此跳出while设置locked=true;this.currentThread=currentThread();
优化,超时后清除blackList
发布于2019年7月7日 16:40:43