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()的更多相关文章

  1. Java多线程中wait, notify and notifyAll的使用

    本文为翻译文章,原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example 在Java的Obje ...

  2. Java多线程的wait(),notify(),notifyAll()

    在多线程的情况下.因为多个线程与存储空间共享相同的过程,同时带来的便利.它也带来了访问冲突这个严重的问题. Java语言提供了一种特殊的机制来解决这类冲突,避免同一数据对象由多个线程在同一时间访问. ...

  3. Java多线程:wait(),notify(),notifyAll()

    1. wait(),notify(),notifyAll() 2. wait() 2.1. wait() 2.2. wait(long timeout) 2.3. wait(long timeout, ...

  4. Java多线程(六) —— 线程并发库之并发容器

    参考文献: http://www.blogjava.net/xylz/archive/2010/07/19/326527.html 一.ConcurrentMap API 从这一节开始正式进入并发容器 ...

  5. 关于java的wait、notify、notifyAll方法

    wait.notify.notifyAll 遇到的问题 之前开发打印机项目,因为需要使用多线程技术,当时并不怎么理解,一开始随意在方法体内使用wait.notify.notifyAll 方法导致出现了 ...

  6. Java Thread wait、notify与notifyAll

    Java的Object类包含了三个final方法,允许线程就资源的锁定状态进行通信.这三个方法分别是:wait(),notify(),notifyAll(),今天来了解一下这三个方法.在任何对象上调用 ...

  7. 线程:Java中wait、notify、notifyAll使用详解

    基础知识 首先我们需要知道,这几个都是Object对象的方法.换言之,Java中所有的对象都有这些方法. public final native void notify(); public final ...

  8. Java线程的wait(), notify()和notifyAll()

    Java线程生命周期 类java.lang.Thread包含一个静态的State enum用于定义每种可能的状态. 在任意的时间点, 线程会处于以下的状态之一: NEW – 新创建的线程, 还未启动( ...

  9. Java面试题之notify和notifyAll的区别

    锁池: 假设线程A已经拥有对象锁,线程B.C想要获取锁就会被阻塞,进入一个地方去等待锁的等待,这个地方就是该对象的锁池: 等待池: 假设线程A调用某个对象的wait方法,线程A就会释放该对象锁,同时线 ...

  10. java 多线程(wait/notify/notifyall)

    package com.example; public class App { /* wait\notify\notifyAll 都属于object的内置方法 * wait: 持有该对象的线程把该对象 ...

随机推荐

  1. C/C++使用libcurl库发送http请求(get和post可以用于请求html信息,也可以请求xml和json等串)

    C++要实现http网络连接,需要借助第三方库,libcurl使用起来还是很方便的 环境:win32 + vs2015 如果要在Linux下使用,基本同理 1,下载编译libcurl 下载curl源码 ...

  2. Win8Metro(C#)数字图像处理--2.24二值图像闭运算

    原文:Win8Metro(C#)数字图像处理--2.24二值图像闭运算  [函数名称] 二值图像闭运算函数CloseOperateProcess(WriteableBitmap src) [算法说 ...

  3. Voovan 是一个高性能异步网络框架和 HTTP(Java)

    Voovan 是一个高性能异步网络框架和 HTTP 服务器框架,同时支持 HTTP 客户端抓取.动态编译支持.数据库访问封装以及 DateTime.String.Log.反射.对象工具.流操作.文件操 ...

  4. QML动画概述(几十篇相关博客)

    QML提供了丰富的动画元素,说起动画,无非是给UI增光添彩罢了.在QML中,动画常常与State和Transition联系在一起,这几个概念(下面的例子中都用到了)都比较简单,相关介绍可查看Qt官方文 ...

  5. New,Getmem,ReallocMem联系与区别(转)

    procedure New(var P: Pointer);  {为一个指针变量分配内存,会自动计算指针所指数据结构需要空的空间大小} procedure GetMem(var P: Pointer; ...

  6. 台电P89s mini root教程

    根据论坛内的一些内容再结合自己的使用心得整理如下,本人双11购入P89s mini root成功  自带软件什么的都不见了 以下是个人root过程,有不一样的地方欢迎交流,说实话我也不是很懂 1.升级 ...

  7. Arcgis Server 10.4.1 搭建集群环境

    1.准备工作 Arcgis Server 10.4.1  以及许可一枚 共享存储(通过UNC路径访问,如"\\server1\arcgisserver\") 服务器两台(虚拟机也可 ...

  8. Docker PHP7 Cannot find OpenSSL's <evp.h>

    configure: error: Cannot find OpenSSL's <evp.h>  apt-get install libssl-dev

  9. 分布式流处理框架 Apache Storm —— 编程模型详解

    一.简介 二.IComponent接口 三.Spout     3.1 ISpout接口     3.2 BaseRichSpout抽象类 四.Bolt     4.1 IBolt 接口     4. ...

  10. 文件识别浅谈(含office文件区分)

    前言 本文主要根据后台接口识别Office文件类型这一话题做一些分享,主要方向还是放在不能获取到文件名情况下的Office文件识别. 可获取到文件名 如果后端接口可以获取到完成的文件名称,则整个过程会 ...