synchronized加锁过程
保证线程同步的方法(线程通信的方法),wait/notify ,synchronized,Reentranklock,,
我所认为的认为的synchronized,锁的膨胀过程,这是一个怎样的概念:无锁状态>偏向锁>轻量级锁>重量级锁;
首先来说说为什么是这样设定(我所认为的),首先来说说对象头吧,其实我只知道冰山一角,我导入一个jar包,jol-core-0.8.jar,这个jar包可以去查看我们的对象头,今天以64位计算机来说,我们先创建一个最简单的对象,
public class L {private String name;
}
对,没错,什么东西都没有,来看看创建一个L的对象的对象头是什么样子
L l=new L();
// l.hashCode();// System.out.println(ClassLayout.parseClass(L.class).toPrintable());System.out.println(ClassLayout.parseInstance(L.class).toPrintable());
OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) df 03 00 20 (11011111 00000011 00000000 00100000) (536871903)
这里只是截取了对象头,采用小端,可以看出,在64为操作系统,一个对象对象头为96bit,(对象头由俩个词组成,Mark Word,Klass Pointer(类的元数据地址,方法区的类的模板信息))
其中Mark Word为64bit,Klass Pointer为32bit
都知道一个对象由对象头+实例数据+填充数据,构成,对象头主要有一个对象的锁状态,hash值,分代年龄等构成
一个对象锁状态,也是在对象头中有2个bit所保存(还有GC标记也有一位),一共是三位所保存;
在jdk1.6之前synchronized是一把重量级锁,(它只要有线程竞争就会有cup的用户态和内核态之间的转变),所以才出现了一个ReentrankLock的锁,而这个锁性能在jdk1.6之前是要比sychronized的性能好很多的,ReentrankLock详解在后续文章中;在jdk1.6之后,oracle将synchronized优化,也就是我们所说的锁的膨胀过程;我们一个状态一个状态的说:
偏向锁:适用于线程少或者线程不竞争(交替执行,一个完了,下一个才来),当一个线程经过同步代码块或同步方法时,会去加锁(假设目前无锁状态),那么如何加呢?首先没有被加锁时,这个对象或者类对象的对象头标记为无锁状态,当第一个线程,线程1来时,可以直接加锁,那么这个对象的对象头就变为偏向锁状态;即这个线程的线程id会被记录在被锁住对象的对象头中,这就是一个偏向线程1的偏向锁,即使这个线程执行完,退出了同步方法,仍然不会去释放锁(所以锁的膨胀过程时不可逆的),这个锁仍然是偏向这个线程的偏向锁,而这个线程下次在进入这个同步方法时,只需要判断当前对象的对象头的线程id与当前线程的线程id相同否,相同则直接进入,不同则判断对象头中保存的线程id对应的线程是否执行完毕(是否已经退出同步),如果执行完毕,则将对象头中的线程id改为当前线程的线程id,当前线程进入(
同样,执行完后也不会释放锁),如果上一个线程还没有执行完,则此时就是竞争的状态而非交替了,锁膨胀为轻量级锁;
那么为什么引入偏向锁呢?
同一个线程只需加锁一次,可以重复进出,不需要花费大量时间去加锁,解锁,同时这个被加锁的线程“被偏向了”,即这个线程进出快
轻量级锁:
上述说到,如果有线程竞争时,锁膨胀为轻量级锁,同样我们先来说说这个加锁过程又是怎么样的,轻量级锁,即这个被锁住的对象的对象头的俩位bit改变,(01.10.11.00)此时为轻量级锁,当第二个线程来竞争时,如果线程1执行完了,则线程2进入,加锁:虚拟机首先在这个线程的栈帧中创建一个名为锁记录(lock Record)的空间,用于储存当前线程的Mark Word 的拷贝Displaced Mark Word,也就是说相当于将对象头中的hash值,分代年龄,锁状态等拷贝一份,然后虚拟机将使用cas操作去将对象头中的Mark Word 更新为一个指向Displaced Mark Word的指针,再将Displaced Mark Word中的锁状态改为轻量级锁,如图:
如果线程1还在同步快中,线程2也不会阻塞,由轻量级锁的缘故,线程2会去进行一定次数的自旋,为什么是自旋呢?还是一个道理,让其阻塞会涉及内核的转变,会十分消耗性能,在线程竞争不激烈时(即少量线程在竞争时),让等待进入的少量线程去自旋要比让其去阻塞的性能要好很多,因为自旋相当于就是让这些等待的线程去尝试获取锁(即循环获取锁,知道成功为止),在只有少量线程竞争时,自旋好一些。当线程很多在竞争时,就膨胀为重量级锁
重量级锁:就是jdk1.6之前的锁,让所有等待的线程全部去阻塞,也就是让他们由操作系统做线程上下文的切换,由用户态转变为内核态,性能很低,但为了保证同步,只有这样,因为当很多线程竞争时,大量线程自旋会耗费大量cpu,所以让其阻塞吧
synchronized是一把非公平锁,即所有等待全部去竞争锁,没有先后之分,上述所说线程加锁,对象加锁,其实是一个概念,我们都知道一句话:被锁住的是对象,所以我们针对的是同一个对象的不同线程来加锁(如果是不同对象,就没有同步可言了);
以上所述,为笔者学习笔记,仅作参考
synchronized加锁过程相关推荐
- 偏向锁、轻量级锁、重量级锁加锁过程即锁升级膨胀过程
偏向锁.轻量级锁.重量级锁加锁过程即锁升级膨胀过程 synchronized 偏向锁 为什么要引入偏向锁 偏向锁加锁过程 线程获取到锁对象的偏向锁之后,执行完同步代码块之后,会释放这个偏向锁吗 使用了 ...
- Mysql加锁过程详解(3)-关于mysql 幻读理解
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- Mysql加锁过程详解(2)-关于mysql 幻读理解
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- Java多线程中使用ReentrantLock、synchronized加锁 简单举例
Java多线程中使用ReentrantLock.synchronized加锁 简单举例 public class Demo {final static Lock lock = new Reentran ...
- java对象头_我的并发编程(二):java对象头以及synchronized升级过程
一.概述 研究java对象头的目的是详细分析Java的synchronized锁的升级过程,因为synchronized在锁升级的时候,就是依赖对象头的信息来决定的.本博文针对64位的操作系统来对Ja ...
- synchronized 加锁 this 和 class 的区别!
作者 | 王磊 来源 | Java中文社群(ID:javacn666) 转载请联系授权(微信ID:GG_Stone) synchronized 是 Java 语言中处理并发问题的一种常用手段,它也被我 ...
- ReadWriteLock读写锁加锁过程
读写锁案例 + 小小总结 //读这篇文章的时候,建议先看一下,我并发专题中的 Lock.lock() 加锁的过程的文章 //我在写读写锁的时候,好多东西,好多理念都在lock()中体现 // 读读串行 ...
- java 静态方法枷锁_Java synchronized静态方法使用synchronized加锁
昆明达内Java培训的老师上一期讲了Java synchronized实例方法使用synchronized加锁,这一期给同学们讲Java synchronized静态方法使用synchronized加 ...
- java synchronized加锁 或者redis锁不起作用
前几天在代码中需要加锁 使用了synchronized 以及redis锁均一直不起作用 , 寻找几天后发现是因为在Controller层加了@Transactional(rollbackFor = E ...
- 【169期】面试官:同学,分析一下MySQL/InnoDB的加锁过程吧
程序员的成长之路 互联网/程序员/技术/资料共享 关注 阅读本文大概需要 17 分钟. 来自:cnblogs.com/crazylqy/p/7611069.html Hello,大家好,我是良月柒. ...
最新文章
- Android’s PreferenceActivity for all API versions
- chmod 755 是李鬼(转)
- Oracle八大性能视图之v$sort_usage_temp
- POJ 3259 Wormholes【最短路/SPFA判断负环模板】
- 额!Java中用户线程和守护线程区别这么大?
- docker tomcat启动无法进入欢迎页面
- fun-函数的数据类型小结
- 苹果x来电闪光灯怎么设置_苹果6splus来电没有声音,苹果6sp听筒没有声音怎么回事...
- 如何去学习linux
- vlang: 新语言尝试,初生牛犊,未来可期
- STM32电机库5.4开源注释 KEIL工程文件 辅助理解S STM32电机库5.4开源注释
- 在Ubuntu中安装Python科学计算环境
- 三十三、Fluent边界条件湍流参数设置详解
- 下载youtube 字幕
- 天猫总裁靖捷详解新零售:传统商圈平均增长超50%
- C语言 | 文件打开关闭
- Android studio百度地图SDK开发 2020最新超详细的Android 百度地图开发讲解(3) 路线规划步行骑行驾车路线规划
- 常微分方程-变量分离、变量变换、线性微分方程和常数变易法
- uniapp中字体加粗问题
- 遗传算法:交叉操作 Position-based Crossover (PBX)
热门文章
- 记一次hive 报错NoViableAltException(-1@[215:51: ( KW_AS )?])
- 在设计软件测试用例的原则,设计软件测试用例需要遵循的四条原则
- 软件开发中如何评估工作量
- Geos库学习之(一)——Geos库介绍和编译
- 通信协议(一)——UART协议
- 未能成功加载扩展程序_JVM类加载 - 大碗炸酱面
- 复杂美科技有限公司区块链专利
- 我的移动开发春季历程,大厂面试题汇总
- Helix QAC软件下载安装使用试用
- PSO最佳适应度收敛曲线