javaEE——synchronized关键字
目录
- 前言
- 1. synchronized特性
- 2. synchronized的使用
- 2.1 修饰实例方法
- 2.2 修饰静态方法
- 2.3 同步代码块
- 3. synchronized的锁机制
- 总结
前言
在前面已经零零散散的介绍了synchronized关键字,这篇文章对其进行总结。
1. synchronized特性
在JDK1.8,synchronized有如下特性:
- 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁.
- 开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁.
- 实现轻量级锁的时候⼤概率⽤到的⾃旋锁策略
- 是一种不公平锁
- 是一种可重入锁
- 不是读写锁
2. synchronized的使用
某个线程执⾏到某个对象的 synchronized 中时, 其他线程如果也执⾏到同⼀个对象 synchronized 就会阻塞等待.
进⼊ synchronized 修饰的代码块, 相当于 加锁
退出 synchronized 修饰的代码块, 相当于 解锁
2.1 修饰实例方法
public synchronized void method() {// 同步代码
}
锁对象是当前实例对象(this)
同一实例的同步方法在同一时刻只能被一个线程访问
2.2 修饰静态方法
public static synchronized void staticMethod() {// 同步代码
}
锁对象是当前类的Class对象(类锁)
所有实例的同步静态方法在同一时刻只能被一个线程访问
2.3 同步代码块
// 锁对象是obj
synchronized(obj) {// 同步代码
}
// 锁对象是当前实例
synchronized(this) {// 同步代码
}// 锁对象是类的Class对象
synchronized(ClassName.class) {// 同步代码
}
可以更细粒度地控制同步范围
可以指定任意对象作为锁
3. synchronized的锁机制
在上篇文章说到,JVM将synchronized分为无锁、偏向锁、轻量级锁、重量级锁状态,会依次进行升级。
-
无锁状态:对象刚创建时的状态
-
偏向锁:
适用于只有一个线程访问同步块的场景
通过CAS操作在对象头和栈帧中记录线程ID(实际上并没有加锁,只是做了个标记)
同一线程再次进入时无需同步操作 -
轻量级锁(自旋锁):
当有多个线程轻度竞争时
通过CAS操作将对象头中的Mark Word替换为指向锁记录的指针,如果更新成功,则认为加锁成功。
如果线程通过自旋尝试获取锁,避免线程阻塞 -
重量级锁:
当竞争激烈时,自旋不能快速获取到锁状态
使用操作系统的互斥量(mutex)实现
执行加锁操作,先进入内核态,判定当前锁是否被占用
如果没有被占用,则加锁成功,切换回用户态
如果被占用,线程则是未获取锁的状态,对于未获取锁的线程,挂起,进入阻塞状态。
总结
本篇文章系统的总结了synchronized关键字,看完这篇文章后,希望你能对这个关键字有更加透彻的理解。