前言
上一篇文章我们讲了java的同步代码块, 这一篇我们来看看同步代码块之间的协作与通信.
阅读本篇前你需要知道什么是同步代码块, 什么是监视器锁, 还不是很了解的同学建议先去看一看上一篇文章.
概述
在Java中, 我们可以使用
wait()
wait(long timeout)
wait(long timeout, int nanos)
notify()
notifyAll()
这5个方法来实现同步代码块之间的通信, 注意, 我说的是同步代码块之间的
通信, 这意味着:
调用该方法的当前线程必须持有对象的监视器锁(源码注释: The current thread must own this object’s monitor.)
其实, 这句话换个通俗点的说法就是: 只能在同步代码块中使用这些方法.
**
道理很简单, 因为只有进入了同步代块, 才能获得监视器锁.
wait
方法的作用是, 阻塞当前线程(阻塞的原因常常是一些必要的条件还没有满足), 让出监视器锁, 不再参与锁竞争, 直到其他线程来通知(告知必要的条件已经满足了), 或者直到设定的超时等待时间到了.
notify
和notifyAll
方法的作用是, 通知那些调用了wait
方法的线程, 让它们从wait
处返回.
可见, wait
和 notify
方法一般是成对使用的, 我把它简单的总结为:
等通知> <br />
wait
是等, notify
是通知.
为了给大家一个感性的认识, 我这里打个比方:
假设你和舍友一起租了个两室一厅一厨一卫的房子, 天这么热, 当然每天都要洗澡啦, 但是卫生间只有一个, 同一时间, 只有一个人能用.
这时候, 你先下班回来了, 准备要洗澡, 刚进浴室, 突然想起来你的专用防脱洗发膏用完了, 查了下快递说是1小时后才能送到, 但这时候你的舍友回来了, 他也要洗澡, 所以你总不能”站着茅坑不拉屎”吧, 所以你主动让出了
浴室(调用wait方法, 让出监视器锁), 让舍友先洗, 自己等
快递.
过了一个小时, 快递送来了你的防脱洗发膏(调用了nofity方法, 唤醒在wait中的线程), 你现在需要洗澡的资源都有了, 万事俱备, 就差进入浴室了, 这个时候你去浴室门口一看, 嘿, 浴室空着!(当前没有线程占用监视器锁) 舍友已经洗好了! 于是你高高兴兴的带着你的防脱洗发水进去洗澡了(再次获得监视器锁).
当然, 上面还有另外一种情况, 假如你不知道快递员什么时候会来, 可能在一小时后, 也可能是明天, 那总不能一直干等着不洗澡吧, 于是你决定, 我就等一个小时(调用带超时时间的wait(long timeout)
方法), 一小时后快递还不来, 就不等了, 大不了用沐浴露凑合着洗洗头 o(TヘTo)
源码分析
以上5个都方法定义在了java的Object类中, 这意味着java中所有的类都会继承这些方法.
同时, 下面的源码分析中我们将看到, 这些方法都是final
类型的, 也就是说所有的子类都不能改写这些方法.
wait方法
public final void wait() throws InterruptedException {
wait(0);
}
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
public final native void wait(long timeout) throws InterruptedException;
wait方法共有三个, 我们发现, 前两个方法都是调用了最后一个方法, 而最后一个方法是一个native
方法.
我们知道, native方法是非java代码实现的, 我们看不到它的具体实现内容, 但是java规定了该方法要实现什么样的功能, 即它应该在java代码里”看起来是什么样子的”.
所以native方法就像java的接口一样, 但是具体实现由JVM直接提供,或者(更多情况下)由外部的动态链接库(external dynamic link library)提供,然后被JVM调用。
在Object的源码的注释中, 描述了该native方法”看起来应该是什么样子的”, 我们一段一段来看:
(这里我把原文也贴出来了, 是怕自己翻译的不够精确, 英语好的可以直接看原文)