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. .NET CORE EnvironmentVariable

    .NET CORE System variables SETIn System variablese.g1:Variable name: ASPNETCORE_ENVIRONMENTVariable ...

  2. 树莓派3B 无显示器,无键盘,无Linux系统,无网线 配置WIFI连接

    #1.基本需求#2.烧写镜像#3.用有线网(网线)连接PC,实现远程操作树莓派#4.接入无线网,通过其它电脑远程控制树莓派#5.使用PC共享的热点Wifi远程控制树莓派 #1.基本需求 树莓派 USB ...

  3. Advanced Installer 打包后,安装包在WIN10下重启后再次运行安装的解决办法

    原文:Advanced Installer 打包后,安装包在WIN10下重启后再次运行安装的解决办法 前几个月使用Advanced Installer 打包了一堆安装包,其中有使用默认主题的,也有根据 ...

  4. 【MVC 笔记】MVC 自定义 Attribute 属性中的猫腻

    原想在 MVC Action 上加一个自定义 Attribute 来做一些控制操作,最先的做法是在自定 Attribute 中定义一个属性来做逻辑判断,可惜事与愿违,这个属性值居然会被缓存起来,于是于 ...

  5. Qt 5.6 5.8 vs2015 编译静态库版本(有全部的截图)good

    安装Qt 去Qt官网下载Qt安装包  安装Qt和源码,一定要勾选source选项  添加bin到系统变量  工具 需要python3和 perl. vs2015 第三方工具,到官方下载安装  在命令行 ...

  6. Jetbrains 工具集

    http://www.jetbrains.com/ PRODUCTS IntelliJ IDEA ReSharper WebStorm PhpStorm PyCharm RubyMine AppCod ...

  7. QTcpSocket类和QTcpServer类

    QTcpSocket 详细描述:QTcpSocket 类提供一个TCP套接字TCP是一个面向连接,可靠的的通信协议,非常适合于连续不断的数据传递QTcpSocket 是QAbstractSocket类 ...

  8. 查看linux系统时间和时区

    参考地址:http://lidao.blog.51cto.com/ 一.使用date命令查看系统时间 [root@benbang ~]# date -R Tue, 01 Aug 2017 15:43: ...

  9. 附005.Kubernetes身份认证

    一 Kubernetes访问 1.1 Kubernetes交互 与Kubernetes交互通常有kubectl.客户端(Dashboard).REST API请求. 1.2 API访问流程 用户使用k ...

  10. .NET CORE与Spring Boot编写控制台程序应有的优雅姿势

    本文分别说明.NET CORE与Spring Boot 编写控制台程序应有的“正确”方法,以便.NET程序员.JAVA程序员可以相互学习与加深了解,注意本文只介绍用法,不会刻意强调哪种语言或哪种框架写 ...