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: 持有该对象的线程把该对象 ...
随机推荐
- IDEA 自动化配置
# IDEA maven web项目:http://www.cnblogs.com/Sinte-Beuve/p/5730553.html # IDEA 数据库自动化 ## 功能 ① SQL 代码自动感 ...
- CORS 专题
CORS(跨域资源共享,Cross-Origin Resource Sharing)CORS其实出现时间不短了,它在维基百科上的定义是:跨域资源共享(CORS )是一种网络浏览器的技术规范,它为Web ...
- C#字符串操作,转自韩迎龙博客
1.1 字符串大小写 方法原型 string <strName>.ToUpper(); //返回字符串转换的大写形式 string <strName>.ToLower( ...
- linux 用蓝牙和手机通信
加载模块: # modprobe hci_usb # modprobe rfcomm # hciconfig hci0 up # hciconfig hci0 up 查看状况: # hci ...
- Windows 上静态编译 Libevent 2.0.10 并实现一个简单 HTTP 服务器(无数截图)
[文章作者:张宴 本文版本:v1.0 最后修改:2011.03.30 转载请注明原文链接:http://blog.s135.com/libevent_windows/] 本文介绍了如何在 Window ...
- 什么是TOML?
配置文件的使用由来已久,从.ini.XML.JSON.YAML再到TOML,语言的表达能力越来越强,同时书写便捷性也在不断提升. TOML是前GitHub CEO, Tom Preston-Werne ...
- UWP中String 转为Path Data
定义方法: Geometry PathMarkupToGeometry(string pathMarkup) { string xaml = "<Path " + " ...
- ASP.NET MVC视图
前言 视图即是用户与Web应用程序的接口,用户通常会看到视图,然后在视图上进行交互,Web应用程序的视图通常是HTML格式. 首先了解控制器选择返回哪个视图的问题.新建一个项目,浏览到/Home/Ab ...
- 演练:创建和使用动态链接库 (C++)
我们将创建的第一种类型的库是动态链接库 (DLL). 使用 DLL 是一种重用代码的绝佳方式. 您不必在自己创建的每个程序中重新实现同一例程,而只需对这些例程编写一次,然后从需要该功能的应用程序引用它 ...
- Long Shadows Generate是一款在线使用纯CSS3实现长阴影的效果,一款强大的扁平化长投影制造器。
Long Shadows Generate是一款在线使用纯CSS3实现长阴影的效果,一款强大的扁平化长投影制造器. Long Shadows Generate 彩蛋爆料直击现场 Long Shadow ...