先来看个奇怪的demo

public class A {
int i=0;
// boolean flag =false;
public synchronized void parse(){
i++;
JOLExample6.countDownLatch.countDown();
}
}

睡眠5秒,测试

public class JOLExample3 {
static A a;
public static void main(String[] args) throws Exception {
Thread.sleep(5000);
a= new A();
//a.hashCode();
out.println("befor lock");
out.println(ClassLayout.parseInstance(a).toPrintable());//无锁:偏向锁?
synchronized (a){
out.println("lock ing");
out.println(ClassLayout.parseInstance(a).toPrintable());
} out.println("after lock");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
}

我注释的那行代码是什么锁?看下结果

可以看出,没有线程持有锁的时候,是可偏向状态

然后我们把睡眠的代码注释掉,再测试一下

//Thread.sleep(5000);

看下结果

再看个两个线程的demo

首先是两个线程交替执行:

public class JOLExample10 {
static A a;
public static void main(String[] args) throws Exception {
a= new A();
Thread t1 = new Thread(){
@Override
public void run() {
synchronized (a){
out.println("t1 lock ing");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
};
t1.start();
Thread.sleep(10000);//睡眠10秒,让main线程和t1线程交替执行
synchronized (a){//a b c c+++
out.println("main lock ing");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
out.println("after lock");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
}

看下结果

可以看出,交替执行时,是轻量锁

我们把睡眠的代码注释掉

//Thread.sleep(5000);//睡眠10秒,让main线程和t1线程交替执行

再次测试,

public class JOLExample10 {
static A a;
public static void main(String[] args) throws Exception {
a= new A();
Thread t1 = new Thread(){
@Override
public void run() {
synchronized (a){
out.println("t1 lock ing");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
};
t1.start();
//Thread.sleep(5000);//睡眠10秒,让main线程和t1线程交替执行
synchronized (a){//a b c c+++
out.println("main lock ing");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
Thread.sleep(5000);//睡眠10秒
out.println("after lock");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
}

看下结果

自旋

自旋一段时间,可以理解为空转,时间很短,具体时间需要看jvm源码,如果在自旋时间内拿到了锁,就不再膨胀,如果还是拿不到锁,则膨胀为重量锁,如下

public static void main(String[] args) throws Exception {
a= new A();
Thread t1 = new Thread(){
@Override
public void run() {
synchronized (a){
out.println("t1 lock ing");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
};
t1.start();
Thread.sleep(1670);//睡眠10秒,让main线程和t1线程交替执行
synchronized (a){//自旋一段时间,可以理解为时间很短,具体时间需要看jvm源码,如果在自旋时间内拿到了锁,就不再膨胀,如果还是拿不到锁,则膨胀为重量锁
out.println("main lock ing");
out.println(ClassLayout.parseInstance(a).toPrintable());
} Thread thread2 = new Thread(){
@Override
public void run() {
synchronized (a){
out.println("t2 lock ing");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
};
thread2.start();
/*Thread.sleep(10);
synchronized (a){
out.println("main lock ing");
out.println(ClassLayout.parseInstance(a).toPrintable());
}*/
//Thread.sleep(5000);//睡眠10秒,让main线程和t1线程交替执行
out.println("after lock");
out.println(ClassLayout.parseInstance(a).toPrintable());
}

如果调用wait方法,则立即变成重量锁

看下demo

public class JOLExample11 {
static A a;
public static void main(String[] args) throws Exception {
//Thread.sleep(5000);
a = new A();
out.println("befre lock");
out.println(ClassLayout.parseInstance(a).toPrintable()); Thread t1= new Thread(){
public void run() {
synchronized (a){
try {
synchronized (a) {
System.out.println("before wait");
out.println(ClassLayout.parseInstance(a).toPrintable());
a.wait();//如果调用wait方法,则立即变成重量锁
System.out.println(" after wait");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
Thread.sleep(7000);
synchronized (a) {
a.notifyAll();
}
}
}

看下结果

我们再看个synchronized膨胀的奇怪特性

让偏向锁无延迟启动

-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
public class JOLExample12 {
static List<A> list = new ArrayList<A>();
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
public void run() {
for (int i=0;i<10;i++){
A a = new A();
synchronized (a){
System.out.println("111111");
list.add(a);
}
} } };
t1.start();
t1.join();
out.println("befre t2");
//偏向
out.println(ClassLayout.parseInstance(list.get(1)).toPrintable());
Thread t2 = new Thread() {
int k=0;
public void run() {
for(A a:list){
synchronized (a){
System.out.println("22222");
if (k==4){
out.println("t2 ing");
//轻量锁
out.println(ClassLayout.parseInstance(a).toPrintable()); }
}
k++;
} }
};
t2.start();
}
}

t1线程new10个对象,t2线程取第五个,看下结果

我们把new对象的数量改一下,改成20个,再来试一下

public class JOLExample12 {
static List<A> list = new ArrayList<A>();
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
public void run() {
for (int i=0;i<20;i++){
A a = new A();
synchronized (a){
System.out.println("111111");
list.add(a);
}
} } };
t1.start();
t1.join();
out.println("befre t2");
//偏向
out.println(ClassLayout.parseInstance(list.get(1)).toPrintable());
Thread t2 = new Thread() {
int k=0;
public void run() {
for(A a:list){
synchronized (a){
System.out.println("22222");
if (k==19){
out.println("t2 ing");
//轻量锁
out.println(ClassLayout.parseInstance(a).toPrintable()); }
}
k++;
} }
};
t2.start();
}
}

这里我们取第20个对象,查看对象头信息

我们可以看到,居然重偏向了,这里是jvm做的优化,20次以后就会冲偏向,小于20次时膨胀为轻量锁

这里我们称之为批量偏向,下面我们看下这个的原理

最后总结一下:轻量锁释放的时候将mark word重置为无锁状态,附上网络上的图

java-锁膨胀的过程的更多相关文章

  1. JAVA锁的优化和膨胀过程

    转自:https://www.cnblogs.com/dsj2016/p/5714921.html https://cloud.tencent.com/developer/article/103675 ...

  2. java并发笔记之四synchronized 锁的膨胀过程(锁的升级过程)深入剖析

    警告⚠️:本文耗时很长,先做好心理准备,建议PC端浏览器浏览效果更佳. 本篇我们讲通过大量实例代码及hotspot源码分析偏向锁(批量重偏向.批量撤销).轻量级锁.重量级锁及锁的膨胀过程(也就是锁的升 ...

  3. java架构之路(多线程)synchronized详解以及锁的膨胀升级过程

    上几次博客,我们把volatile基本都说完了,剩下的还有我们的synchronized,还有我们的AQS,这次博客我来说一下synchronized的使用和原理. synchronized是jvm内 ...

  4. JAVA锁的膨胀过程和优化

    首先说一下锁的优化策略. 1,自旋锁 自选锁其实就是在拿锁时发现已经有线程拿了锁,自己如果去拿会阻塞自己,这个时候会选择进行一次忙循环尝试.也就是不停循环看是否能等到上个线程自己释放锁.这个问题是基于 ...

  5. JAVA锁的膨胀过程和优化(阿里)

    阿里的人问什么是锁膨胀,答不上来,回来做了总结: 关于锁的膨胀,synchronized的原理参考:深入分析Synchronized原理(阿里面试题) 首先说一下锁的优化策略. 1,自旋锁 自旋锁其实 ...

  6. synchronized(三) 锁的膨胀过程(锁的升级过程)深入剖析

    警告⚠️:本文耗时很长,先做好心理准备................哈哈哈 本篇我们讲通过大量实例代码及hotspot源码分析偏向锁(批量重偏向.批量撤销).轻量级锁.重量级锁及锁的膨胀过程(也就是 ...

  7. synchronized的实现原理——锁膨胀过程

    @ 目录 前言 正文 偏向锁 轻量锁 批量重偏向 批量撤销 重量锁 总结 前言 上一篇分析了优化后的synchronized在不同场景下对象头中的表现形式,还记得那个结论吗?当一个线程第一次获取锁后再 ...

  8. JAVA锁有哪些种类,以及区别(转)

    在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲观锁 分段锁 偏向锁/轻量级 ...

  9. Java 锁优化

    一.重量级锁   Java中,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的.而操作系统实现 ...

  10. JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,

    如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...

随机推荐

  1. C 实战练习题目1

    题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 实例: #in ...

  2. 用libevent写个简单的server/client

    libevent是一个轻量级的事件触发库,可以很好地利用在网络通讯上面,用其进行大量的异步,延时,重发等场景. 下面是一个server的demo #include include void cb_fu ...

  3. git本地库中配置多个sshkey

    一般来说正常情况下本地库中配置一个sshkey就可以适应开发了,但是生活中总会有那么一点点的小惊喜.由于公司业务的发展,现在需要本地库中再配置一个sshkey,下面记录下配置的全过程: 生成并添加第一 ...

  4. 树形dp技巧,多叉树转二叉树

    今天复习树形dp时发现一道比较古老的题,叫选课,是树形dp的一道基础题,也是多叉树转二叉树应用的模版题 多叉树转二叉树的应用非常广泛,因为如果一个节点的儿子太多,一个一个存下来不方便去查询,并且会增加 ...

  5. Java常用类__装箱/拆箱

    以下是常用的各两种方法(各类提供了构造方法,静态方法) 一.基本数据类型 转化为 包装类(装箱) 例:int i=10: Integer num=i;//num=10 二.包装类 转化为  基本数据类 ...

  6. PostgreSql 自定义函数:批量调整某个字段长度

    CREATE or replace FUNCTION alterColumn(cloumnName VARCHAR(32), out v_retcode text)AS$BODY$ declare r ...

  7. Android | 教你如何用代码开发一个拍照翻译小程序

    引子   想必有很多小伙伴喜欢外出旅游,能去海外玩一圈那是更好不过了,旅游前大家一定会对吃.穿.住.行.游玩路线做各种攻略,然后满怀期待的出发- 想象中的旅游   出发前,想象中的旅游目的地可能有漂亮 ...

  8. dict字典的用法

    在用dict遇到了一些困难,记一下. 代码1: books={"倚天屠龙记":{"id":1,"price":100}, "好吗好 ...

  9. 关于代码覆盖 or 冲突

    关于代码覆盖 or 冲突 在使用git同步代码时,步骤一般为 commit -> pull -> push 那这个过程的意义何在呢? 首先是区分本地仓库 与 远程仓库,可以理解为本地git ...

  10. Vue点击当前元素添加class 去掉兄弟的class

    <div id="app"> <ul> <li v-for="(todo, index) in todos" v-on:click ...