synchronized中wait、notify的原理与源码

1.wait和notify的流程图

2.JVM源码

java层面wait的方法

 public final native void wait(long timeout) throws InterruptedException;

jvm中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},
};

jvm层面wait方法的源码

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()) {//默认为false
JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);
}
ObjectSynchronizer::wait(obj, ms, CHECK);//主要方法是wait
JVM_END

ObjectSynchronizer::wait

// -----------------------------------------------------------------------------
// Wait/Notify/NotifyAll
// NOTE: must use heavy weight monitor to handle wait()
int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
if (UseBiasedLocking) {//使用偏向锁
BiasedLocking::revoke_and_rebias(obj, false, THREAD);//撤销偏向锁,因为第二个参数为false;该方法在synchronized的文章中已经做过介绍了
}
if (millis < 0) {//超时就抛出异常
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
}
//wait方法需要先将锁膨胀到重量级锁
ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD,
obj(),
inflate_cause_wait); DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
monitor->wait(millis, true, THREAD);//插入等待队列中等待 // This dummy call is in place to get around dtrace bug 6254741. Once
// that's fixed we can uncomment the following line, remove the call
// and change this function back into a "void" func.
// DTRACE_MONITOR_PROBE(waited, monitor, obj(), THREAD);
return dtrace_waited_probe(monitor, obj, THREAD);
}

ObjectMonitor::wait

void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
Thread * const Self = THREAD;//获取当前线程对象
JavaThread *jt = (JavaThread *)THREAD;//获取当前线程对应的java线程对象
EventJavaMonitorWait event; Self->_Stalled = intptr_t(this);//设置当前线程阻塞在该 ObjectMonitor上
jt->set_current_waiting_monitor(this); ObjectWaiter node(Self);//生成节点
node.TState = ObjectWaiter::TS_WAIT;//修改状态
Self->_ParkEvent->reset();
OrderAccess::fence(); //全屏障保证后续可以读取到最新值 Thread::SpinAcquire(&_WaitSetLock, "WaitSet - add");//获取_WaitSetLock
AddWaiter(&node);//将等待的节点插入waitset中
Thread::SpinRelease(&_WaitSetLock);//释放_WaitSetLock _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(true, Self); // exit the monitor 退出重量级锁 int ret = OS_OK;
int WasNotified = 0;
{ // State transition wrappers
OSThread* osthread = Self->osthread();
OSThreadWaitState osts(osthread, true);//将os线程置为OBJECT_WAIT的状态
{
ThreadBlockInVM tbivm(jt);//设置当前对应的java线程是阻塞状态;_thread_blocked = 10, // blocked in vm
// Thread is in thread_blocked state and oop access is unsafe.
jt->set_suspend_equivalent(); if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) {//中断或者异常唤醒不做处理
// Intentionally empty
} else if (node._notified == 0) {//如果唤醒的信号==0;去阻塞
if (millis <= 0) {//如果设置的等待时间<=0
Self->_ParkEvent->park();//阻塞等待唤醒
} else {
ret = Self->_ParkEvent->park(millis);//超时等待,到时间自动醒过来
}
} // were we externally suspended while we were waiting?
if (ExitSuspendEquivalent (jt)) {
// TODO-FIXME: add -- if succ == Self then succ = null.
jt->java_suspend_self();
} } // Exit thread safepoint: transition _thread_blocked -> _thread_in_vm if (node.TState == ObjectWaiter::TS_WAIT) {//如果当前状态时TS_WAIT
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - unlink");//获取_WaitSetLock锁
if (node.TState == ObjectWaiter::TS_WAIT) {
DequeueSpecificWaiter(&node); // 将当前node等待节点从waitset中摘除
node.TState = ObjectWaiter::TS_RUN;//修改状态为TS_RUN
}
Thread::SpinRelease(&_WaitSetLock);//释放_WaitSetLock锁
} OrderAccess::loadload();//使用读屏障,刷新内存中的值 OrderAccess::fence(); Self->_Stalled = 0;//将阻塞对象置为空 ObjectWaiter::TStates v = node.TState;//获取节点状态
if (v == ObjectWaiter::TS_RUN) {//如果节点状态为TS_RUN,去获取锁
enter(Self);
} else {
ReenterI(Self, &node);//尝试去获取锁
node.wait_reenter_end(this);//将线程设置为可运行状态
}
} // OSThreadWaitState() jt->set_current_waiting_monitor(NULL); _recursions = save; // restore the old recursion count 值还原
_waiters--; // decrement the number of waiters 等待节点减1 if (!WasNotified) {//如果不是被唤醒的
// no, it could be timeout or Thread.interrupt() or both
// check for interrupt event, otherwise it is timeout
if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {//中断产生的直接抛出异常
THROW(vmSymbols::java_lang_InterruptedException());
}
}
}

JVM_MonitorNotify和JVM_MonitorNotifyAll

JVM_ENTRY(void, JVM_MonitorNotify(JNIEnv* env, jobject handle))
JVMWrapper("JVM_MonitorNotify");
Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
ObjectSynchronizer::notify(obj, CHECK);//关键方法是notify
JVM_END JVM_ENTRY(void, JVM_MonitorNotifyAll(JNIEnv* env, jobject handle))
JVMWrapper("JVM_MonitorNotifyAll");
Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
ObjectSynchronizer::notifyall(obj, CHECK);//关键方法是notifyAll
JVM_END

ObjectSynchronizer::notify和ObjectSynchronizer::notifyall

void ObjectSynchronizer::notify(Handle obj, TRAPS) {
if (UseBiasedLocking) {//偏向锁直接撤销
BiasedLocking::revoke_and_rebias(obj, false, THREAD);
}
markOop mark = obj->mark();//轻量级锁直接进行替换头部
if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
return;
}
//锁膨胀直接调用notify方法
ObjectSynchronizer::inflate(THREAD,
obj(),
inflate_cause_notify)->notify(THREAD);
} // NOTE: see comment of notify()
void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
if (UseBiasedLocking) {//偏向锁直接撤销
BiasedLocking::revoke_and_rebias(obj, false, THREAD);
}
markOop mark = obj->mark();//轻量级锁直接进行替换头部
if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
return;
}
//锁膨胀直接调用notifyAll方法
ObjectSynchronizer::inflate(THREAD,
obj(),
inflate_cause_notify)->notifyAll(THREAD);
}

ObjectMonitor::notify和 ObjectMonitor::notifyAll

void ObjectMonitor::notify(TRAPS) {
if (_WaitSet == NULL) {//等待集合为空直接返回
return;
}
DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);
INotify(THREAD);//唤醒当前线程
OM_PERFDATA_OP(Notifications, inc(1));
} void ObjectMonitor::notifyAll(TRAPS) {
if (_WaitSet == NULL) {//等待集合为空直接返回
return;
}
DTRACE_MONITOR_PROBE(notifyAll, this, object(), THREAD);
int tally = 0;
while (_WaitSet != NULL) {//while循环挨个唤醒
tally++;
INotify(THREAD);
} OM_PERFDATA_OP(Notifications, inc(tally));
}

ObjectMonitor::INotify

void ObjectMonitor::INotify(Thread * Self) {
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - notify");//获取_WaitSetLock锁
ObjectWaiter * iterator = DequeueWaiter();//第一个节点出队
if (iterator != NULL) {
iterator->TState = ObjectWaiter::TS_ENTER;//修改状态为TS_ENTER iterator->_notified = 1;//标识唤醒线程数为1
iterator->_notifier_tid = JFR_THREAD_ID(Self);//记录唤醒的线程di ObjectWaiter * list = _EntryList;//获取_EntryList执行队列 // prepend to cxq 执行队列为空,将竞争队列中的任务批量移动到_EntryList中
if (list == NULL) {
iterator->_next = iterator->_prev = NULL;
_EntryList = iterator;
} else {
iterator->TState = ObjectWaiter::TS_CXQ;//否则修改节点状态为TS_CXQ
for (;;) {//保证出队的节点插入到等待队列中
ObjectWaiter * front = _cxq;
iterator->_next = front;
if (Atomic::cmpxchg(iterator, &_cxq, front) == front) {
break;
}
}
}
iterator->wait_reenter_begin(this);
}
Thread::SpinRelease(&_WaitSetLock);//释放_WaitSetLock锁 }

4.留言

这些只是个人整理的知识点,中间可能有不到位的地方,烦请各位大佬指出

synchronized中wait、notify的原理与源码的更多相关文章

  1. JDK1.8中LinkedList的实现原理及源码分析

    详见:https://blog.csdn.net/cb_lcl/article/details/81222394 一.概述           LinkedList底层是基于双向链表(双向链表的特点, ...

  2. Java并发包中Semaphore的工作原理、源码分析及使用示例

    1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后 ...

  3. 详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]

    目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumen ...

  4. 【MVC - 参数原理】详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]

    前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/spring ...

  5. 2、JDK8中的HashMap实现原理及源码分析

    本篇提纲.png 本篇所述源码基于JDK1.8.0_121 在写上一篇线性表的文章的时候,笔者看的是Android源码中support24中的Java代码,当时发现这个ArrayList和Linked ...

  6. JDK1.8中ArrayList的实现原理及源码分析

    一.概述 ArrayList是Java开发中使用比较频繁的一个类,通过对源码的解读,可以了解ArrayList的内部结构以及实现方法,清楚它的优缺点,以便我们在编程时灵活运用. 二.源码分析 2.1 ...

  7. JDK8中的HashMap实现原理及源码分析

    大纲 一.什么是Hash?什么是HashMap? 二.HashMap的内部实现机制 1.HashMap基本元素 ①DEFAULT_INITIAL_CAPACITY&MAXIMUM_CAPACI ...

  8. ConcurrentHashMap实现原理及源码分析

    ConcurrentHashMap实现原理 ConcurrentHashMap源码分析 总结 ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现(若对Ha ...

  9. HashMap和ConcurrentHashMap实现原理及源码分析

    HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...

  10. (转)ReentrantLock实现原理及源码分析

    背景:ReetrantLock底层是基于AQS实现的(CAS+CHL),有公平和非公平两种区别. 这种底层机制,很有必要通过跟踪源码来进行分析. 参考 ReentrantLock实现原理及源码分析 源 ...

随机推荐

  1. mumpy常用函数

    numpy.array(list(1,2,3,4)) #将一个list类型/tupe类型数据转换为一个array数组对象 #默认所有的数据类型都是相同,若传进来的参数类型不同,则遵循以下优先级: st ...

  2. pandas之窗口函数

    为了能更好地处理数值型数据,Pandas 提供了几种窗口函数,比如移动函数(rolling).扩展函数(expanding)和指数加权函数(ewm).窗口函数应用场景非常多.举一个简单的例子:现在有 ...

  3. 【开源免费】ChatGPT-Java版SDK重磅更新至1.0.10版,支持Tokens计算,快来一键接入。

    简介 ChatGPT Java版SDK开源地址:https://github.com/Grt1228/chatgpt-java ,目前收获将近1000个star. 有bug欢迎朋友们指出,互相学习,所 ...

  4. day117:MoFang:宠物栏的功能实现&宠物道具的使用

    目录 1.宠物栏的功能实现 2.宠物道具的使用 1.宠物栏的功能实现 1. 宠物的显示 2. 宠物的使用 3. 宠物的饱食度 4. 宠物的开锁 1.服务端提供显示宠物的api接口 orchard/so ...

  5. 使用laravel开发微信公众的一个大坑,适合新手学习的laravel接入微信接口

    最近使用laravel做微信公众号二次开发,发现网上能够参考的资料基本上很少,很多地方都讲的不够详细,致使许多新手采坑无数,所以这篇文章讲一下如何使用laravel接入微信接口,实现微信公众号二次开发 ...

  6. javasec(四)序列化与反序列化基本原理

    title: javasec(四)序列化与反序列化基本原理 tags: - javasec - 反序列化 categories: - javasec cover: 'https://blog-1313 ...

  7. js中数组的sort() 方法

    sort()  方法用于对数组的元素进行排序,并返回数组.默认排序顺序是根据字符串UniCode码.因为排序是按照字符串UniCode码的顺序进行排序的,所以首先应该把数组元素都转化成字符串(如有必要 ...

  8. Redis之消息队列实现

    文章目录 秒杀场景 采用消息队列实现 List实现消息队列 PubSub(发布订阅)实现消息队列 基于Stream实现消息队列 消费者组 实践 总结 秒杀问题是非常重要且比较难实现的,如果不进行架构的 ...

  9. DataX更换python3,File “datax.py“, line 114 print readerRef

    datax 报错 File "datax.py", line 114 print readerRef 报错: File "datax.py", line 114 ...

  10. 【解决方法】windows连接域时报错:An Active Directory Domain Controller(AD DC) for the domain“chinaskills.com“....

    目录-快速跳转 问题描述 原因分析: 解决方案: 附言: 问题描述 操作环境与场景: 在 VM 内 windos 2019 在连接到域时,提示报错: An Active Directory Domai ...