温故知新-多线程-深入刨析synchronized
- Posted by 微博@Yangsc_o
- 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
文章目录
摘要
本文从synchronized的基本用法,结合对象的内存布局,深入探究synchronized的锁升级的过程,探究其实现原理。准备开始~
synchronized的基础用法
修饰普通同步⽅方法
对于非static的情况,synchronized是对象级别的,其实质是将synchronized作用于对象引用(object reference)上,即拿到p1对象锁的线程,对的fun()方法有同步互斥作用,不同的对象之间坚持“和平共处”。
// 锁的对象是方法的调用者
public synchronized void method(){ }
上边的示例代码等同于如下代码:
public void method() {
synchronized (this) { }
}
修饰静态同步方法
如果方法用static修饰,synchronized的作用范围就是class一级的,它对类的所有对象起作用。
Class Foo{
public static synchronized void method1() {
}
}
上边的示例代码等同于如下代码:
public void method2()
{
synchronized(Foo.class) {
// class literal(类名称字面常量)
//请注意,Foo.class也是一个对象,类型是Class,在一个ClassLoader里,它是唯一的。
}
}修饰同步代码块
锁就是so这个对象,谁拿到这个锁谁就能够运行他所控制的那段代码。
同步块,示例代码如下:
public void method(SomeObject so) {
synchronized(so)
{
//…..
}
}
当有一个明确的对象作为锁时,就能够这样写代码,但当没有明确的对象作为锁,只是想让一段代码同步时,能够创建一个特别的instance变量(它得是个对象)来充当锁
class Foo implements Runnable{
private byte[] lock = new byte[0]; // 特别的instance变量
Public void method(){
synchronized(lock) { }
}
- 注:零长度的byte数组对象创建起来将比任何对象都经济。查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
特殊说明
- 使⽤用synchronized修饰类和对象时,由于类对象和实例例对象分别拥有⾃自⼰己的监视器器锁,因此不不会
相互阻塞 - 使⽤synchronized修饰实例例对象时,如果一个线程正在访问实例例对象的一个synchronized方法时,其它线程不仅不能访问该synchronized⽅法,该对象的其它synchronized方法也不不能访问,因为一个对象只有一个监视器器锁对象,但是其它线程可以访问该对象的非synchronized⽅法。
synchronized原理
字节码理解
在说synchronized原理时,就不得不先了解一下Monitor
认识 Java Monitor Object
Java Monitor 从两个方面来支持线程之间的同步,即:互斥执行(对象内的所有方法都互斥的执行。好比一个 Monitor 只有一个运行许可,任一个线程进入任何一个方法都需要获得这个许可,离开时把许可归还)与协作(通常提供signal机制:允许正持有许可的线程暂时放弃许可,等待某个监视条件成真,条件成立后,当前线程可以通知正在等待这个条件的线程,让它可以重新获得运行许可)。 Java 使用对象锁 ( 使用 synchronized 获得对象锁 ) 保证工作在共享的数据集上的线程互斥执行 , 使用 notify/notifyAll/wait 方法来协同不同线程之间的工作。这些方法在 Object 类上被定义,会被所有的 Java 对象自动继承。
Java 语言对于这样一个典型并发设计模式做了内建的支持,线程如果获得监视锁成功,将成为该监视者对象的拥有者。在任一时刻内,监视者对象只属于一个活动线程 (Owner) 。拥有者线程可以调用 wait 方法自动释放监视锁,进入等待状态。下图很好地描述了 Java Monitor 的工作机理。
在Java虚拟机(HotSpot)中, monitor是由ObjectMonitor实现的,其主要数据结构如下(位于HotSpot虚拟机源码ObjectMonitor.hpp⽂文件,C++实现的),位于/openjdk-8u60/hotspot/src/share/vm/runtime/objectMonitor.hpp
ObjectMonitor() {
_header = NULL; //markOop对象头
_count = 0; // 可以⼤大于1,可重⼊入
_waiters = 0, //等待线程数
_recursions = 0; //重⼊入次数
_object = NULL; //监视器器锁寄⽣生的对象。锁不不是平⽩白出现的,⽽而是寄托存储于对象中。
_owner = NULL; //初始时为NULL表示当前没有任何线程拥有该monitor record,当线程成功拥有该锁后保存线程唯⼀一标识,当锁被释放时⼜又设置为NULL
_WaitSet = NULL; //处于wait状态的线程,会被加⼊入到_WaitSet
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ; //处于等待锁block状态的线程,会被加⼊入到该列列表
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
_previous_owner_tid = 0;
}
每个线程都有两个ObjectMonitor对象列列表,分别为free和used列列表,如果当前free列列表为空,线程将
向全局global list请求分配ObjectMonitor。thread结构/openjdk-8u60/hotspot/src/share/vm/runtime/thread.hpp
// Private thread-local objectmonitor list - a simple cache organized as a SLL.
public:
ObjectMonitor* omFreeList;
int omFreeCount; // length of omFreeList
int omFreeProvision; // reload chunk size
ObjectMonitor* omInUseList; // SLL to track monitors in circulation
int omInUseCount; // length of omInUseList
ObjectMonitor中有两个队列列, _WaitSet 和 _EntryList,用来保存ObjectWaiter对象列列表( 每个等待锁的线程都会被封装成ObjectWaiter对象), owner指向持有ObjectMonitor对象的线程,当多个线程同时访问一段同步代码时,首先会进⼊入 EntryList 集合,当线程获取到对象的monitor 后进⼊ _Owner 区域并把monitor中的owner变量量设置为当前线程同时monitor中的计数器器count加1,若线程调⽤用 wait() ⽅法,将释放当前持有的monitor, owner变量量恢复为null, count⾃自减1,同时该线程进⼊入 WaitSet集合中等待被唤醒。若当前线程执⾏行行完毕也将释放monitor(锁)并复位变量量的值,以便便其他线程进⼊入获取monitor(锁)。
由此看来, monitor对象存在于每个Java对象的对象头中(存储的指针的指向), synchronized锁便是通过这种⽅式获取锁的,也是为什么Java中任意对象可以作为锁的原因。
代码验证
是不是一脸崩?不知道在说什么
温故知新-多线程-深入刨析synchronized的更多相关文章
- 温故知新-多线程-深入刨析volatile关键词
文章目录 摘要 volatile的作用 volatile如何解决线程可见? CPU Cache CPU Cache & 主内存 缓存一致性协议 volatile如何解决指令重排序? volat ...
- 温故知新-多线程-深入刨析CAS
文章目录 摘要 CAS是什么? CAS是如何实现的? CAS存在的问题? 你的鼓励也是我创作的动力 Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 ...
- 温故知新-多线程-深入刨析park、unpark
文章目录 摘要 park.unpark 看一下hotspot实现 参考 你的鼓励也是我创作的动力 Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | ...
- 温故知新-多线程-Cache Line存在验证
文章目录 简述 缓存行Cache Line 验证CacehLine存在? 参考 你的鼓励也是我创作的动力 Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持 ...
- 深入刨析tomcat 之---第8篇 how tomcat works 第11章 11.9应用程序,自定义Filter,及注册
writed by 张艳涛, 标签:全网独一份, 自定义一个Filter 起因:在学习深入刨析tomcat的学习中,第11章,说了调用过滤链的原理,但没有给出实例来,自己经过分析,给出来了一个Filt ...
- 深入刨析tomcat 之---第2篇,解决第3章bug 页面不显示内容http://localhost:8080/servlet/ModernServlet?userName=zhangyantao&password=1234
writedby 张艳涛7月2日, 在学习第4张的过程中,发现了前一篇文章写的是关于1,2张的bug不用设置response响应头,需要在servlet的service()方法里面写是错误想 serv ...
- Orchard 刨析:Logging
最近事情比较多,有预研的,有目前正在研发的,都是很需要时间的工作,所以导致这周只写了两篇Orchard系列的文章,这边不能保证后期会很频繁的更新该系列,但我会写完这整个系列,包括后面会把正在研发的东西 ...
- Orchard 刨析:Caching
关于Orchard中的Caching组件已经有一些文章做了介绍,为了系列的完整性会再次对Caching组件进行一次介绍. 缓存的使用 在Orchard看到如下一段代码: 可以看到使用缓存的方法Get而 ...
- Orchard 刨析:导航篇
之前承诺过针对Orchard Framework写一个系列.本应该在昨天写下这篇导航篇,不过昨天比较累偷懒的去玩了两盘单机游戏哈哈.下面进入正题. 写在前面 面向读者 之前和本文一再以Orchard ...
随机推荐
- 【雕爷学编程】MicroPython动手做(05)——零基础学MaixPy之LCD液晶屏
配套 2.4寸LCD屏 ST7789驱动器芯片(24P 320X240) ST7789驱动器芯片2.4寸LCD屏(24P 320X240)主要参数 1. 模块名称:液晶显示模块2. 型号:KD024C ...
- table动态添加的tr 其click事件在IE兼容模式中不执行 jquery 1.9 的live事件 和获取 first last
http://www.css88.com/jqapi-1.9/first-of-type/index.html#p=//www.css88.com/jqapi-1.9/last-child-selec ...
- SpringMVC笔记总结
文章所有代码见:gitee 1.回顾MVC 1.1.什么是MVC MVC是模型(Model).视图(View).控制器(Controller)的简写,是一种软件设计规范. 是将业务逻辑.数据.显示分离 ...
- Yii2.0 URL美化功能Nginx与Apache配置文件
NGinx: location / { index index.html index.htm index.php; try_files $uri $uri/ /index.php$is_args$ar ...
- Kubernetes学习笔记(八):Deployment--声明式的升级应用
概述 本文核心问题是:如何升级应用. 对于Pod的更新有两种策略: 一是删除全部旧Pod之后再创建新Pod.好处是,同一时间只会有一个版本的应用存在:缺点是,应用有一段时间不可用. 二是先创建新Pod ...
- 【JUC】阻塞队列&生产者和消费者
阻塞队列 线程1往阻塞队列添加元素[生产者] 线程2从阻塞队列取出元素[消费者] 当队列空时,获取元素的操作会被阻塞 当队列满时,添加元素的操作会被阻塞 阻塞队列的优势:在多线程领域,发生阻塞时,线程 ...
- 【GAN】GAN设计与训练集锦
以下内容纯属经验之谈,无公式推断!部分内容源自其他博客或课程,并已标注来源. 问题篇[1] 1.模式崩溃 在某个模式(mode)下出现大量重复样本,如左图中,生成的样本分布靠得很近,较聚集,可视化如右 ...
- Black Hat Python之#1:制作简单的nc工具
nc即netcat,是网络界的瑞士军刀.当入侵了一个服务器之后,发现nc工具已经被系统管理员移除之后,可以自己制作一个简单的客户端和服务器端来实现①上传文件②执行命令③开启一个新的命令行shell等几 ...
- 关于ueditor编译器
取消自动保存提示.edui-editor-messageholder.edui-default{ visibility:hidden;} Qiyuwen 1033935470@qq.com
- background-color的覆盖范围
1. 一般div的background-color覆盖范围 到 border,margin的颜色由外层元素决定 2. body的background-color覆盖范围 到 margin,但 当htm ...