java基础---多线程---synchronized实现原理
Posted buptyuhanwen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java基础---多线程---synchronized实现原理相关的知识,希望对你有一定的参考价值。
synchronized用于三个地方。
修饰普通方法,那么线程需要获取对象锁。
修饰静态方法,那么线程需要获取类锁,其实就是Class对象。类锁和对象锁之间互不干扰。
修改代码块,也要获取对象锁。
用于代码块的时候对应monitorenter指令和monitorexit指令,表示需要获取monitor锁才能够执行这个代码块
用于方法的时候,方法区方法的flag参数中就有一个ACC_SYNCHRONIZED标示,表示线程想要执行这个方法就必须先获取monitor锁。
对于monitor锁,每个对象都有一个monitor锁。这个锁在hotspot虚拟机中是用c++实现的一个objectMonitor对象数据结构,他维护了两个队列同步队列和等待队列,有点像AQS的两个队列。多个线程同时要获取这个锁的时候就进入同步队列,同时通过一个指针指向获取到锁的线程,同时有个计数器count用来做锁重入的计数器。调用wait方法的时候线程进入等待队列。
blog.csdn.net/yinbucheng/article/details/72524482
要了解synchronized需要了解对象头的概念。
===java对象在内存中存了哪三个部分数据?对象头中存了哪两个信息?
包括对象头,实例数据,对齐填充
对象头最重要两个部分:mark word,类型指针
1.mark word里面有公共的部分包括hashcode,GC分代年龄,锁状态码表示对象的几种锁状态。随着锁状态的不同,mark word会呈现出不同的结构。
偏向锁的时候存的就是获取偏性锁的线程id
轻量级锁的时候就是指向线程栈锁记录的指针。
比如重量级锁就存了指向对象锁monitor的指针,对象锁monitor是c++实现的一种数据结构。
2.类型指针,确定对象是什么类的实例。
有哪些锁状态呢?
synchronized引入锁升级以及不同的锁状态,目的就是为了减少获取锁和释放锁的性能消耗
===对象头中的mark word都有哪些个状态?锁状态码都对应了锁的哪些状态呢?
锁状态有4中
01---无锁(是否为偏向锁标志为0),
偏向锁:mark word存的是获取锁的线程的id
00---轻量级锁,保存了指向线程栈锁记录的指针。
10---重量级锁,保存了monitor对象的指针
锁可以不断升级,而且不能回头。
锁升级过程
===偏向锁适用条件?
适用于不存在锁竞争的情况下同一个线程反复获取锁的场景。
这个线程获取到偏向锁的时候,mark word会记录这个线程的id,这样同一个线程获取锁就不需要任何处理了,不需要用CAS去获取或者释放锁。
但是存在锁竞争的时候,其他线程也想要这个锁的时候就变成轻量级锁,markword的结构也变了。
===轻量级锁适用的条件?
适用于线程交替执行同步代码块的情况,也是不存在锁竞争的前提下。
轻量级锁有指向线程栈中锁记录区的指针。线程的栈帧中创建lock record锁记录区域,锁记录区也有指针指向mark word。他们相互指向。
如果获取轻量级锁失败了,就会尝试使用自旋锁。
===适应性自旋锁?
在线程获取轻量级锁的过程中失败了,为了避免第一次失败就挂起,线程就会自旋一定的次数尝试再次获取。如果还是不能获取到锁就升级成重量级锁。
===锁粗化(lock coarsening)
当涉及到一个线程反复对同一个对象加锁和解锁的操作的时候,就会将这个过程合并成一个更大范围的加锁和解锁操作。
6 public void append(){
7 stringBuffer.append("a");
8 stringBuffer.append("b");
9 stringBuffer.append("c");
10 }
会在第一个append处加锁,在最后一次append处释放锁。
===锁消除适用场景?禁用锁消除的JVM指令?
减少一些不必要的加锁。一般涉及到方法内局部变量的可以进行锁消除。比如方法内创建局部变量stringbuilder循环一万次append一个字符,这种append本身是要加锁的但是这边因为是局部变量其他线程碰不到可以进行锁消除。
for (int i = 0; i < 100000000; i++) {
13 test02.append("abc", "def");
14 }
public void append(String str1, String str2) {
19 StringBuffer sb = new StringBuffer();
20 sb.append(str1).append(str2);
21 }
以上是关于java基础---多线程---synchronized实现原理的主要内容,如果未能解决你的问题,请参考以下文章