《Java高并发编程详解-多线程架构与设计》线程间的通信

摘自《Java高并发编程详解-多线程架构与设计》第五章

文章目录

    • 同步、异步、阻塞、非阻塞概念
    • Monitor锁
      • wait 与 notify
      • 使用wait的注意事项
      • 使用notify的注意
    • 例子:
        • 测试主动interrupt对if中使用wait的影响
    • wait与sleep的
    • synchronized的缺点
    • 利用wait、notify实现可中断的BooleanLock

同步、异步、阻塞、非阻塞概念

同步和异步
结果的通知机制。自己问还是别人通知。
同步:主动等待结果的返回。如阻塞等待,轮询(同步非阻塞)。
异步:被动等待结果的返回。如 消息回调。

阻塞和非阻塞
结果返回以前,调用方的状态。等还是不等。
阻塞:结果返回以前,什么也不干。

非阻塞:在结果返回以前,可以先做一些其他事情。

Monitor锁

下面所说的获取monitor锁都是指的先使用synchronized获取对象锁
不应该叫synchronized(mutex)为锁,而应该是某个线程获取了与mutex关联的monitor锁。

wait 与 notify

wait 理解成线程在等待直到该对象可用。(被notify后就不再等待)

notify理解成线程通知该对象可用。

使用wait的注意事项

  1. wait必须在同步方法中使用,因为wait必须由拥有monitor(已用synchronize获取锁)的线程调用。

  2. wait可以被中断,为了防止wait被interrupt唤醒,wait方法需要在循环中使用。

  3. 使用wait后自动释放线程对应的锁。–release ownership of this monitor

  4. wait会等待直到其他线程调用notify/notifyAll唤醒。–waits until anthoer thread notifies threads waiting on this object’s monitor to wake up…

  5. 被notify/notifyAll唤醒后会重新获得锁的拥有权,然后接着执行。–re-obtain ownership of the monitor and resumes execution.

  6. 线程调用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 ()
    * 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的注意

  1. 必须在同步方法中使用wait、notify,因为他们的使用前提都是持有monitor所有权。

  2. 同步代码块的monitor必须与执行 wait 、notify的对象一致,也就是说对哪个对象同步,才能调用那个对象的 wait、notify。

例子:

若不是用的notifyAll, 则不能用于多线程环境

《Java高并发编程详解-多线程架构与设计》线程间的通信_第1张图片
《Java高并发编程详解-多线程架构与设计》线程间的通信_第2张图片
while而不是if中调用wait!否则一旦被interrupt,会跳过判断继续执行。如
《Java高并发编程详解-多线程架构与设计》线程间的通信_第3张图片

测试主动interrupt对if中使用wait的影响

这里主动interrupt,可见当producer被interrupt后,producer就略过了判断,继续添加了一个event

《Java高并发编程详解-多线程架构与设计》线程间的通信_第4张图片

wait与sleep的

  • 相同:
    使线程阻塞
    可以中断
  • 不同:
    wait是Object的方法,sleep是Thread的
    wait必须要在同步代码块中执行。
    wait会释放monitor的锁,sleep不会
    sleep短暂休眠后会退出阻塞?(TODO)wait(没有指定时间的话)必须被中断才会退出阻塞。

synchronized的缺点

  1. 无法中断
    synchronized不像sleep和wait那样,可以被中断。

  2. 没有等待时间
    其他线程获取锁的拥有权必须要等待锁的拥有者(线程)释放后才能执行。

利用wait、notify实现可中断的BooleanLock

p96-104
一旦从wait中被唤醒则有机会检查lock是否为false,为false则修改获取锁的线程cureentLockThread为自己,并设置lock为true.防止其他线程继续争抢。
如果wait超时会报错,notify后超时 也主动抛错。

关键代码

《Java高并发编程详解-多线程架构与设计》线程间的通信_第5张图片

从wait中被notify或者等待超时后,会因为while(locked),locked为false,说明没有线程持有monitor的拥有权,因此跳出while设置locked=true;this.currentThread=currentThread();
《Java高并发编程详解-多线程架构与设计》线程间的通信_第6张图片
优化,超时后清除blackList
《Java高并发编程详解-多线程架构与设计》线程间的通信_第7张图片

发布于2019年7月7日 16:40:43

你可能感兴趣的:(Java,读书笔记)