java synchronized 同步锁

基本用法

普通方法

对于普通方法,锁是当前实例对象,也就是this
一般为new或者newInstance创建的实例对象

public synchronized void commonMethod() {
    System.out.println("synchronized 修饰 普通 方法 ");
}

静态方法

对于静态方法,锁是Class对象

public static synchronized void staticMethod() {
    System.out.println("synchronized 修饰 静态 方法 ");
}

同步代码块

对于同步代码块,锁是同步代码块里面的对象
如下代码中,锁是当前实例对象

public void syncMethodBlock() {
    synchronized (this) {
        System.out.println("synchronized 修饰 代码块");
    }
}

同步代码块

1、 每个对象都有一个监视器(Monitor)与它相关联,执行monitorenter指令的线程将获得与object ref关联的监视器的所有权。线程获取锁。
2、如果另一个线程已经拥有与object ref 关联的监视器,则当前线程将等待直到对象被解锁为止。线程等待锁。
3、拥有锁的线程,执行monitorexit指令,将移除与object ref 关联的监视器的所有权。线程释放锁。
3、通过 monitorenter 和 monitorexit 指令来实现java语言的同步代码块。

同步方法

1、在运行时常量池里通过ACC_SYNCHRONIZED来区分是否是同步方法,方法执行时会检查该标志。
2、当一个方法有这个标志时,进入的线程首先需要获取监视器才能执行该方法。
3、方法结束或者抛出异常时会释放监视器。

对象的内存布局

1、常见的虚拟机中,对象由对象头,实例数据,以及对齐填充位三部分组成。
2、对象头会存储该对象运行时数据,包括哈希码,GC分代年龄,锁状态(无锁,偏向锁,轻量级锁,重量级锁),是否偏向锁,偏向线程ID等信息。存储上述这些的区域叫做 Mark Word(标记词)。
3、对象头还有一部分区域用来存储类型指针,可以通过该类型指针来定位对象的元数据信息。JVM通过这个指针确定该对象是哪个类的实例。

锁升级

1、当只有一个线程访问时叫做偏向锁。

a、偏向锁的偏向是指同步代码会一直偏向第一个调用它的线程,直到有别的线程过来竞争这把锁。
b、在第一次调用同步代码并获得锁时会在对象头和栈帧 锁记录行(Lock Record)里存储偏向线程ID,该线程再次进入的时候就不需要重新申请锁了。只需要检测对象头的Mark Word里是否存储着指向该偏向线程的ID即可。
c、当有线程来竞争这把锁的时候,偏向锁会撤销偏向。

2、发生竞争的时候升级成轻量级锁(自旋等待)。

a、当有竞争且竞争不强烈时,JVM就会由偏向锁膨胀为轻量级锁
b、线程的阻塞和唤醒需要CPU从用户态转变为核心态,会增加CPU负担,因此没有获取到锁的线程不会进入阻塞状态,而是通过自旋的方式一直尝试获取锁,处于一种忙等的状态。
c、自旋等待,这种处理竞争的方式比较浪费CPU,但是响应速度很快。
d、多个线程竞争锁,按到达的顺序来排队,叫做公平锁;不排队,叫做不公平锁。

4、多次(默认10次)自旋等待没结果的时候升级成重量级锁。

a、线程多次自旋未能获取锁,线程阻塞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我以前不抽烟的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值