Java多线程(六):wait(),notify()和notifyAll()
wait(),notify()和notifyAll()介绍
1.wait()
使当前线程等待,直到另一个线程调用notify(),notifyAll()或者中断,当前线程调用wait()之前必须持有锁,调用wait()之后会释放锁。等到当前线程重新获得锁,恢复执行。
只能在同步方法调用wait()。
2.notify()
唤醒一个正在等待锁的线程,如果有多个线程在等待锁,那么任意唤醒其中一个wait的线程。被唤醒的线程(wait的线程)只有在当前线程(notify的线程)释放锁后才可以执行。
只能在同步方法调用notify()。
3.notifyAll()
唤醒所有正在等待锁的线程。
只能在同步方法调用notifyAll()。
native wait()
openjdk找到src/share/native/java/lang/Object.c
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
}
我们先看下wait
方法
src/share/vm/prims/jvm.cpp
搜索JVM_MonitorWait
JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
JVMWrapper("JVM_MonitorWait");
Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
JavaThreadInObjectWaitState jtiows(thread, ms != 0);
if (JvmtiExport::should_post_monitor_wait()) {
//当前线程拥有锁,尚且没有加入到等待队列,所以要推迟wait()
JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);
}
//进入等待状态
ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END
我们看下ObjectSynchronizer::wait方法
src/share/vm/runtime/synchronizer.cpp
// NOTE: must use heavy weight monitor to handle wait()
void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
//偏向锁校验
if (UseBiasedLocking) {
//撤销偏向锁
BiasedLocking::revoke_and_rebias(obj, false, THREAD);
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
//时间校验
if (millis < 0) {
TEVENT (wait - throw IAX) ;
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
}
//膨胀为重量级锁
ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
monitor->wait(millis, true, THREAD);
dtrace_waited_probe(monitor, obj, THREAD);
}
我们看下monitor->wait方法
src/share/vm/runtime/objectMonitor.cpp
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
Thread * const Self = THREAD ;
assert(Self->is_Java_thread(), "Must be Java thread!");
JavaThread *jt = (JavaThread *)THREAD;
DeferredInitialize () ;
// Throw IMSX or IEX.
CHECK_OWNER();
// check for a pending interrupt 是否有中断信号
if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
// post monitor waited event. Note that this is past-tense, we are done waiting.
if (JvmtiExport::should_post_monitor_waited()) {
// Note: 'false' parameter is passed here because the
// wait was not timed out due to thread interrupt.
JvmtiExport::post_monitor_waited(jt, this, false);
}
TEVENT (Wait - Throw IEX) ;
THROW(vmSymbols::java_lang_InterruptedException());
return ;
}
TEVENT (Wait) ;
assert (Self->_Stalled == 0, "invariant") ;
Self->_Stalled = intptr_t(this) ;
//设置线程的监视锁
jt->set_current_waiting_monitor(this);
// create a node to be put into the queue
// Critically, after we reset() the event but prior to park(), we must check
// for a pending interrupt.
//添加一个节点放入到等待队列中
ObjectWaiter node(Self);
node.TState = ObjectWaiter::TS_WAIT ;
Self->_ParkEvent->reset() ;
OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag
//获取锁
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ;
//添加节点
AddWaiter (&node) ;
//释放锁
Thread::SpinRelease (&_WaitSetLock) ;
if ((SyncFlags & 4) == 0) {
_Responsible = NULL ;
}
intptr_t save = _recursions; // record the old recursion count
//增加等待线程数
_waiters++; // increment the number of waiters
_recursions = 0; // set the recursion level to be 1
exit (Self) ; // exit the monitor
guarantee (_owner != Self, "invariant") ;
......
}
native notify()
我们看下notify()
src/share/vm/prims/jvm.cpp
JVM_ENTRY(void, JVM_MonitorNotify(JNIEnv* env, jobject handle))
JVMWrapper("JVM_MonitorNotify");
Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
ObjectSynchronizer::notify(obj, CHECK);
JVM_END
src/share/vm/runtime/synchronizer.cpp
void ObjectSynchronizer::notify(Handle obj, TRAPS) {
//偏向锁校验
if (UseBiasedLocking) {
BiasedLocking::revoke_and_rebias(obj, false, THREAD);
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
markOop mark = obj->mark();
//检验线程是否有锁
if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
return;
}
ObjectSynchronizer::inflate(THREAD, obj())->notify(THREAD);
}
src/share/vm/runtime/objectMonitor.cpp
void ObjectMonitor::notify(TRAPS) {
CHECK_OWNER();
if (_WaitSet == NULL) {
TEVENT (Empty-Notify) ;
return ;
}
DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);
int Policy = Knob_MoveNotifyee ;
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
ObjectWaiter * iterator = DequeueWaiter() ;
if (iterator != NULL) {
TEVENT (Notify1 - Transfer) ;
guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
guarantee (iterator->_notified == 0, "invariant") ;
if (Policy != 4) {
iterator->TState = ObjectWaiter::TS_ENTER ;
}
iterator->_notified = 1 ;
Thread * Self = THREAD;
iterator->_notifier_tid = Self->osthread()->thread_id();
ObjectWaiter * List = _EntryList ;
if (List != NULL) {
assert (List->_prev == NULL, "invariant") ;
assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
assert (List != iterator, "invariant") ;
}
......
}
//释放锁
Thread::SpinRelease (&_WaitSetLock) ;
if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) {
ObjectMonitor::_sync_Notifications->inc() ;
}
}
native notifyAll()
我们看下notifyAll
和notify()相似
src/share/vm/prims/jvm.cpp
JVM_ENTRY(void, JVM_MonitorNotifyAll(JNIEnv* env, jobject handle))
JVMWrapper("JVM_MonitorNotifyAll");
Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
ObjectSynchronizer::notifyall(obj, CHECK);
JVM_END
我们看下ObjectSynchronizer::notifyall方法
和notify()相似
void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
//偏向锁校验
if (UseBiasedLocking) {
BiasedLocking::revoke_and_rebias(obj, false, THREAD);
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
markOop mark = obj->mark();
//检测线程是否有锁
if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
return;
}
ObjectSynchronizer::inflate(THREAD, obj())->notifyAll(THREAD);
}
src/share/vm/runtime/objectMonitor.cpp
比notify()多了等待队列
void ObjectMonitor::notifyAll(TRAPS) {
CHECK_OWNER();
ObjectWaiter* iterator;
if (_WaitSet == NULL) {
TEVENT (Empty-NotifyAll) ;
return ;
}
DTRACE_MONITOR_PROBE(notifyAll, this, object(), THREAD);
int Policy = Knob_MoveNotifyee ;
int Tally = 0 ;
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notifyall") ;
for (;;) {
iterator = DequeueWaiter () ;
if (iterator == NULL) break ;
TEVENT (NotifyAll - Transfer1) ;
++Tally ;
// Disposition - what might we do with iterator ?
// a. add it directly to the EntryList - either tail or head.
// b. push it onto the front of the _cxq.
// For now we use (a).
guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
guarantee (iterator->_notified == 0, "invariant") ;
iterator->_notified = 1 ;
Thread * Self = THREAD;
iterator->_notifier_tid = Self->osthread()->thread_id();
if (Policy != 4) {
iterator->TState = ObjectWaiter::TS_ENTER ;
}
ObjectWaiter * List = _EntryList ;
if (List != NULL) {
assert (List->_prev == NULL, "invariant") ;
assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
assert (List != iterator, "invariant") ;
}
......
if (Policy < 4) {
iterator->wait_reenter_begin(this);
}
}
//释放锁
Thread::SpinRelease (&_WaitSetLock) ;
if (Tally != 0 && ObjectMonitor::_sync_Notifications != NULL) {
ObjectMonitor::_sync_Notifications->inc(Tally) ;
}
}
wait()和notfiy()实例
MyThread30_0类,使用wait()
public class MyThread30_0 extends Thread {
private Object lock;
public MyThread30_0(Object lock)
{
this.lock = lock;
}
public void run()
{
try
{
synchronized (lock)
{
System.out.println("开始------wait time = " + System.currentTimeMillis());
lock.wait();
System.out.println("结束------wait time = " + System.currentTimeMillis());
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
MyThread30_1类,使用notify()
public class MyThread30_1 extends Thread {
private Object lock;
public MyThread30_1(Object lock)
{
this.lock = lock;
}
public void run()
{
synchronized (lock)
{
System.out.println("开始------notify time = " + System.currentTimeMillis());
lock.notify();
System.out.println("结束------notify time = " + System.currentTimeMillis());
}
}
}
main方法,sleep保证mt0线程先执行。
public class MyThread30_main {
public static void main(String[] args) throws Exception
{
Object lock = new Object();
MyThread30_0 mt0 = new MyThread30_0(lock);
mt0.start();
Thread.sleep(3000);
MyThread30_1 mt1 = new MyThread30_1(lock);
mt1.start();
}
}
运行结果如下
开始------wait time = 1563183002681
开始------notify time = 1563183005683
结束------notify time = 1563183005683
结束------wait time = 1563183005683
先执行“开始------wait time = 1563183002681”,lock.wait()会释放锁,mt0线程进入等待状态。
mt1线程获得锁,执行“开始------notify time = 1563183005683”,lock.notify()唤醒wait的线程(mt0),使mt0退出等待状态,进入可运行状态,mt0线程想要执行必须等待notify的线程(mt1)释放锁,所以执行“结束------notify time = 1563183005683”
最后再恢复执行mt0线程,输出“结束------wait time = 1563183005683”
wait()释放锁
ThreadDomain31类,调用wait方法
public class ThreadDomain31 {
public void testMethod(Object lock)
{
try
{
synchronized (lock)
{
System.out.println(Thread.currentThread().getName() + " Begin wait()");
lock.wait();
System.out.println(Thread.currentThread().getName() + " End wait");
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
MyThread31类
public class MyThread31 extends Thread{
private Object lock;
public MyThread31(Object lock)
{
this.lock = lock;
}
public void run()
{
ThreadDomain31 td = new ThreadDomain31();
td.testMethod(lock);
}
public static void main(String[] args)
{
Object lock = new Object();
MyThread31 mt0 = new MyThread31(lock);
MyThread31 mt1 = new MyThread31(lock);
mt0.start();
mt1.start();
}
}
运行结果如下
Thread-0 Begin wait()
Thread-1 Begin wait()
假如wait()不释放锁,我们应该执行完同步方法,我们应该打印
Thread-1 Begin wait()
Thread-1 End wait
Thread-0 Begin wait()
Thread-0 End wait
反之,证明了wait释放锁,放弃了同步块的执行权。
notify()不释放锁
ThreadDomain32类,用sleep为了说明此时没有其他线程进入同步代码块,即不释放锁。
public class ThreadDomain32 {
public void testMethod(Object lock)
{
try
{
synchronized (lock)
{
System.out.println("Begin wait(), ThreadName = " + Thread.currentThread().getName());
lock.wait();
System.out.println("End wait(), ThreadName = " + Thread.currentThread().getName());
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void synNotifyMethod(Object lock)
{
try
{
synchronized (lock)
{
System.out.println("Begin notify(), ThreadName = " + Thread.currentThread().getName());
lock.notify();
Thread.sleep(5000);
System.out.println("End notify(), ThreadName = " + Thread.currentThread().getName());
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
MyThread32_0类
public class MyThread32_0 extends Thread{
private Object lock;
public MyThread32_0(Object lock)
{
this.lock = lock;
}
public void run()
{
ThreadDomain32 td = new ThreadDomain32();
td.testMethod(lock);
}
}
MyThread32_1类
public class MyThread32_1 extends Thread{
private Object lock;
public MyThread32_1(Object lock)
{
this.lock = lock;
}
public void run()
{
ThreadDomain32 td = new ThreadDomain32();
td.synNotifyMethod(lock);
}
}
输出结果如下
Begin wait(), ThreadName = Thread-0
Begin notify(), ThreadName = Thread-1
End notify(), ThreadName = Thread-1
End wait(), ThreadName = Thread-0
Begin notify(), ThreadName = Thread-2
End notify(), ThreadName = Thread-2
Begin wait()和End notify()紧密相连,我们已经使用了sleep(5000),5s之间足够让其他线程进入同步代码块了,说明notify的线程(mt1和mt2)没有释放锁。
notifyAll()唤醒所有线程
ThreadDomain34类
public class ThreadDomain34 {
public void testMethod(Object lock)
{
try
{
synchronized (lock)
{
System.out.println("Begin wait(), ThreadName = " + Thread.currentThread().getName());
lock.wait();
System.out.println("End wait(), ThreadName = " + Thread.currentThread().getName());
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
MyThread34_0类
public class MyThread34_0 extends Thread {
private Object lock;
public MyThread34_0(Object lock)
{
this.lock = lock;
}
public void run()
{
ThreadDomain34 td = new ThreadDomain34();
td.testMethod(lock);
}
}
MyThread34_1类
public class MyThread34_1 extends Thread{
private Object lock;
public MyThread34_1(Object lock)
{
this.lock = lock;
}
public void run()
{
synchronized (lock)
{
lock.notifyAll();
}
}
}
main方法,启动三个线程并使其wait,启动mt3线程notifyAll
public class MyThread34_main {
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
MyThread34_0 mt0 = new MyThread34_0(lock);
MyThread34_0 mt1 = new MyThread34_0(lock);
MyThread34_0 mt2 = new MyThread34_0(lock);
mt0.start();
mt1.start();
mt2.start();
Thread.sleep(1000);
MyThread34_1 mt3 = new MyThread34_1(lock);
mt3.start();
}
}
输出结果如下
Begin wait(), ThreadName = Thread-0
Begin wait(), ThreadName = Thread-2
Begin wait(), ThreadName = Thread-1
End wait(), ThreadName = Thread-1
End wait(), ThreadName = Thread-2
End wait(), ThreadName = Thread-0
notifyAll方法唤醒处于同一监视器下所有wait状态的线程,启动线程顺序是随机的,唤醒线程的顺序是随机的。
Java多线程(六):wait(),notify()和notifyAll()的更多相关文章
- Java多线程中wait, notify and notifyAll的使用
本文为翻译文章,原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example 在Java的Obje ...
- Java多线程的wait(),notify(),notifyAll()
在多线程的情况下.因为多个线程与存储空间共享相同的过程,同时带来的便利.它也带来了访问冲突这个严重的问题. Java语言提供了一种特殊的机制来解决这类冲突,避免同一数据对象由多个线程在同一时间访问. ...
- Java多线程:wait(),notify(),notifyAll()
1. wait(),notify(),notifyAll() 2. wait() 2.1. wait() 2.2. wait(long timeout) 2.3. wait(long timeout, ...
- Java多线程(六) —— 线程并发库之并发容器
参考文献: http://www.blogjava.net/xylz/archive/2010/07/19/326527.html 一.ConcurrentMap API 从这一节开始正式进入并发容器 ...
- 关于java的wait、notify、notifyAll方法
wait.notify.notifyAll 遇到的问题 之前开发打印机项目,因为需要使用多线程技术,当时并不怎么理解,一开始随意在方法体内使用wait.notify.notifyAll 方法导致出现了 ...
- Java Thread wait、notify与notifyAll
Java的Object类包含了三个final方法,允许线程就资源的锁定状态进行通信.这三个方法分别是:wait(),notify(),notifyAll(),今天来了解一下这三个方法.在任何对象上调用 ...
- 线程:Java中wait、notify、notifyAll使用详解
基础知识 首先我们需要知道,这几个都是Object对象的方法.换言之,Java中所有的对象都有这些方法. public final native void notify(); public final ...
- Java线程的wait(), notify()和notifyAll()
Java线程生命周期 类java.lang.Thread包含一个静态的State enum用于定义每种可能的状态. 在任意的时间点, 线程会处于以下的状态之一: NEW – 新创建的线程, 还未启动( ...
- Java面试题之notify和notifyAll的区别
锁池: 假设线程A已经拥有对象锁,线程B.C想要获取锁就会被阻塞,进入一个地方去等待锁的等待,这个地方就是该对象的锁池: 等待池: 假设线程A调用某个对象的wait方法,线程A就会释放该对象锁,同时线 ...
- java 多线程(wait/notify/notifyall)
package com.example; public class App { /* wait\notify\notifyAll 都属于object的内置方法 * wait: 持有该对象的线程把该对象 ...
随机推荐
- WPF DataGrid自动生成列
<Window x:Class="DataGridExam.MainWindow" xmlns="http://schemas.microsoft.c ...
- 利用WIX制作安装包(1)
原文 利用WIX制作安装包(1) #installation 下载最新版本的WIX toolset 并安装DOWNLOAD Wix toolset V3.5之后的版本已经可以集成到visual stu ...
- 职业规划 - DREAM START
前言 最近面试了好多公司,得出一个结论:做一份详细的计划.一个程序员,不只是写写代码这么简单的事,一种更高的境界则是在代码中.系统的设计中,能找到人生的意义,简单说就是生活的道理.我一直认为:当你在一 ...
- RoboVM 1.1 发布,Java 转原生平台代码
分享 <关于我> 分享 [中文纪录片]互联网时代 http://pan.baidu.com/s/1qWkJfcS 分享 <HTML开发MacOSAp ...
- Long Shadows Generate是一款在线使用纯CSS3实现长阴影的效果,一款强大的扁平化长投影制造器。
Long Shadows Generate是一款在线使用纯CSS3实现长阴影的效果,一款强大的扁平化长投影制造器. Long Shadows Generate 彩蛋爆料直击现场 Long Shadow ...
- QPixmap的缓冲区
我想qt 中QPixmap这个类大家都很熟悉,它可以很简单的在标签上贴图:例如: QPixmap p; p.load("1.png"): label->setPixmap(p ...
- 【Windows Universal Platform】只是学习笔记 - 开始
我是初学,之前没有windows/windows phone的应用开发经验:开博的目的只是记录和督促自己学习. 心血来潮也好,或是个人喜好的原因,想学着自己开发APP了(PS:以前做过web 开发) ...
- NPOI 超简单的导出导入
首先说说,第一次遇到过匿名导出的那个时候是在我在北京第一家公司,简单的声明一个对象就可以导出,那时候感觉高大上,自己也想研究研究,但是因为头将代码后来加密了根本看不到.好吧,研究了研究放弃了,后来 ...
- C++ 王者归来:对编程语言的需求总结为四个:效率,灵活,抽象,生产率(C++玩的是前三个,Java和C#玩的是后两个)
Why C++ ? 王者归来(转载) 因为又有人邀请我去Quora的C2C网站去回答问题去了,这回是 关于 @laiyonghao 的这篇有点争议的博文<2012 不宜进入的三个技术点>A ...
- String的所有方法以及解释
capitalize() 把字符串的第一个字符改为大写 casefold() 把整个字符串的所有字符改为小写 center(width) 将字符串居中,并使用空格填充至长度 width 的新字符串 c ...