synchronized的特性
1. 互斥
synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到同一个对象 synchronized 就会阻塞等待.
进入 synchronized 修饰的代码块, 相当于 加锁
退出 synchronized 修饰的代码块, 相当于 解锁
所有对象都可以作为 synchronized的锁(基本数据类型对象除外).
2. 刷新内存
synchronized 的工作过程 :
- 获得互斥锁
- 从主内存拷贝变量的最新副本到工作的内存
- 执行代码
- 将更改后的共享变量的值刷新到主内存
- 释放互斥锁
synchronized 也能保证内存可见性
3. 可重入
synchronized 对同一条线程来说是可重入的,不会出现自己把自己锁死的问题.
就是在锁里面再加一把锁, 并且两把锁的锁对象都是同一个, 一般来说要想进入第二把锁就得等第一把锁将锁对象释放了, 而第一把锁想释放就得进入并走出第二把锁, 这就产生了矛盾, 产生了死锁. 而 synchronized 并没有这样的问题.
synchronized的使用
synchronized 本质上要修改指定对象的 “对象头”. 从使用角度来看, synchronized 也势必要搭配一个具体的对象来使用.
1. 直接修饰普通方法
public class SynchronizedDemo { public synchronized void methond() { } }
2. 修饰静态方法
public class SynchronizedDemo { public synchronized static void method() { } }
3. 修饰代码块
锁当前对象
public class SynchronizedDemo { public void method() { synchronized (this) { } } }
锁类对象
public class SynchronizedDemo { public void method() { synchronized (SynchronizedDemo.class) { //通过反射来获得对象 } } }
synchronized的锁机制
基本特点
- 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁.
- 开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁.
- 实现轻量级锁的时候大概率用到自旋锁策略.
- 是一种不公平锁 (产生阻塞等待时, 不是按顺序来得到锁)
- 是一种可重入锁.
- 不是读写锁.
关键锁策略 : 锁升级
偏向锁不是真的 “加锁”, 只是打上一个 “标记”, 记录这个锁属于哪个线程.
如果后续没有其他线程来竞争该锁, 那么就不用进行其他操作了(避免了加锁解锁的开销)
如果后续其他线程来竞争这把锁了, 偏向锁就升级为自旋锁(轻量级锁), 如果竞争进一步激烈, 自旋不能快速获取到锁状态, 就会变为重量级锁.