synchronized中wait、notify的原理与源码
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的原理与源码的更多相关文章
- JDK1.8中LinkedList的实现原理及源码分析
详见:https://blog.csdn.net/cb_lcl/article/details/81222394 一.概述 LinkedList底层是基于双向链表(双向链表的特点, ...
- Java并发包中Semaphore的工作原理、源码分析及使用示例
1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后 ...
- 详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]
目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumen ...
- 【MVC - 参数原理】详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]
前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/spring ...
- 2、JDK8中的HashMap实现原理及源码分析
本篇提纲.png 本篇所述源码基于JDK1.8.0_121 在写上一篇线性表的文章的时候,笔者看的是Android源码中support24中的Java代码,当时发现这个ArrayList和Linked ...
- JDK1.8中ArrayList的实现原理及源码分析
一.概述 ArrayList是Java开发中使用比较频繁的一个类,通过对源码的解读,可以了解ArrayList的内部结构以及实现方法,清楚它的优缺点,以便我们在编程时灵活运用. 二.源码分析 2.1 ...
- JDK8中的HashMap实现原理及源码分析
大纲 一.什么是Hash?什么是HashMap? 二.HashMap的内部实现机制 1.HashMap基本元素 ①DEFAULT_INITIAL_CAPACITY&MAXIMUM_CAPACI ...
- ConcurrentHashMap实现原理及源码分析
ConcurrentHashMap实现原理 ConcurrentHashMap源码分析 总结 ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现(若对Ha ...
- HashMap和ConcurrentHashMap实现原理及源码分析
HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...
- (转)ReentrantLock实现原理及源码分析
背景:ReetrantLock底层是基于AQS实现的(CAS+CHL),有公平和非公平两种区别. 这种底层机制,很有必要通过跟踪源码来进行分析. 参考 ReentrantLock实现原理及源码分析 源 ...
随机推荐
- 二进制安装Kubernetes(k8s) v1.24.1 IPv4/IPv6双栈 --- Ubuntu版
二进制安装Kubernetes(k8s) v1.24.1 IPv4/IPv6双栈 --- Ubuntu版本 Kubernetes 开源不易,帮忙点个star,谢谢了 介绍 kubernetes二进制安 ...
- Github 添加贪吃蛇动画
前言 我们都知道,对于Github来说,当你选择你的账户时,可以看到自己的提交记录. 于是就有大神动脑筋了,这些commit记录都是一些豆,如果弄一条蛇来,不就可以搞个贪吃蛇了吗? 有道理有道理,本文 ...
- xtrabackup8.0.27备份失败
问题描述:mysql8.0.27备份出现中断,重新备份发现xtrabackup备份失败,xtrabackup与mysql版本不匹配,后来想起来时mysql进行了升级,8.0.27->8.0.29 ...
- 部署:Mysql8和Mysql5.7部署同一服务器
问题描述:将Mysql8.0.22和Mysql5.7.32部署在同一环境下 操作系统:centos7.8 数据库:Mysql8.0.22.Mysql5.7.32 版本 占用端口 实例名 数据文件 端口 ...
- docker 配置 Mysql主从集群
docker 配置Mysql集群 Docker version 20.10.17, build 100c701 MySQL Image version: 8.0.32 Docker container ...
- 探究公众号接口漏洞:从后台登录口到旁站getshell
探究公众号接口漏洞:从后台登录口到旁站getshell 1.入口 发现与利用公众号接口安全漏洞 某120公众号提供了一处考核平台,通过浏览器处打开该网站. 打开可以看到一处密码登录口,试了一下常用的手 ...
- css中文字与图片对齐
css中文字与图片对齐 第一种,使用vertical-align:middle .icon{ background-repeat:no-repeat; background-position:cent ...
- 【Python毕业设计】基于Python+Flask+MySQL的学生信息管理系统(附完整源码)
1.项目说明基于python+Flask+mysql的学生信息管理系统项目实战 项目需要安装pycharm专业版,mysql数据库以及项目所需的所有模块创建数据库名称db_online_notes,然 ...
- STM32下载ELF文件、最小可执行bin文件测试
1.STM32能下载ELF格式的文件吗? 答:可以.因为所谓的bin文件就是ELF文件的.text代码段. 当然前提是下载工具能识别ELF文件格式,STM32下载ELF文件并不意味着STM32可以把E ...
- Prism Sample 20-NavigateToExistingViews
上一个例子介绍了INavigationAware中的OnNavitationTo,这次是第二个实现函数. IsNavitationTarget,这个名字有点误导,真实的作用是,当从其它页面导航至本页面 ...