历史最优久的使用最方便的线程同步的关键字。必须点赞
一、synchronized 特性
- 同一时刻只有一个线程访问临界资源
- 其它未获取到锁执行权的线程必须排队等待
- 保证共享资源的原子性、可见性和有序性
- 进入synchronized范围内自动加锁,synchronized作用域外锁自动消除,即使异常也会释放锁
- 简单方便(不需要人工释放锁)
- jdk1.6后性能做了很大优化
二、synchronized用法
- 普通方法同步
作用: 所有访问该对象实例该方法的线程,必须排队执行
如: synchronized public void add(){
}
- 静态方法同步
作用: 所有采用类名.方法名访问的线程, 必须排队执行
如: synchronized public static void add(){
}
- 代码块同步
作用: 所有访问到该表达式的线程,必须排队执行
synchronized(表达式){
}
表达式可以是:
a. this 表示该对象,仅适用于非静态方法的情况
b. 类名.class 适用于静态方法和非静态方法
c. 对象实例 适用于静态方法和非静态方法
d. 成员变量 适用于静态方法和非静态方法
三、
synchronized原理
synchronized的底层实现原理都是通过对象头里面的monitor(监视器锁)来实现的。每个对象头里面都有一个指针指向monitor,monitor中又包含有访问计数器,能否进入是根据计数器值来判断的。
- 同步代码块原理
同步代码块是通过monitorenter、monitorexit来控制。 字节码指令如下, 操作原理:
1、当访问到monitorenter时, 当前线程会尝试获取该对象的monitor所有权
获取所有权的依据是monitor的计数器值是否为0, 为0则获取到了,同时将计数器值 +1
2、如果已获取到monitor所有权, 则直接将计数器 +1并进入运行指令阶段
3、如果没有尝试获取该对象的monitor持有权,会进入等待队列进行阻塞
- 同步方法原理
同步方法是通过方法常量池中的方法表关键字来控制, 如果用synchronized修改方法,那么常量池里面会有ACC_SYNCHRONIZEDR进行修饰。
当线程访问加了synchronized的方法时, 会去判断是否有ACC_SYNCHRONIZED标识,
1、如果有该标识, 当前线程会尝试获取该对象的monitor所有权
获取所有权的依据是monitor的计数器值是否为0, 为0则获取到了,同时将计数器值 +1
2、如果已获取到monitor所有权, 则直接将计数器 +1并进入运行指令阶段
3、如果没有尝试获取该对象的monitor持有权,会进入等待队列进行阻塞
四、synchronized可重入性
可重入性也是依据是否可获取monitor持有权来判断。