对象锁和类锁(对象锁和类锁互不影响)
对象锁(同一个类的不同实例对象都有一把自己的锁)
1.作用在实例方法上
public synchronized void method(){}
2.作用在代码块上
public void method(){
synchronized(this){
//这里是需要同步的部分
}
}
3.锁不同对象
synchronized(object1){}
synchronized(object2){}
类锁(同一个类的所有实例对象同一把锁)
1.用synchronized修饰静态方法
public synchronized static void method()
2.作用在代码块上
public void method(){
synchronized(object.class){
}
}
可重入锁(synchronized 与ReentrantLock)
同一个方法中锁两次,或者类里面有两个方法都加了锁
public class Demo {
void method(){
synchronized (this){
//.....
//.....
synchronized (this){
//.....
//.....
}
}
}
}
public class Demo {
synchronized void methodA(){
}
synchronized void methodB(){
}
}
1)可重入特性
ReentrantLock 内部是通过 AQS 实现同步控制的,AQS 有一个变量 state 用于记录同步状态。初始情况下,state = 0,表示 ReentrantLock 目前处于解锁状态。如果有线程调用 lock 方法进行加锁,state 就由0变为1,如果该线程再次调用 lock 方法加锁,就让其自增,即 state++。线程每调用一次 unlock 方法释放锁,会让 state–。通过查询 state 的数值,即可知道 ReentrantLock 被重入的次数了。
(2)抽象队列同步器AbstractQueuedSynchronizer(AQS)
在 AQS 内部,通过维护一个FIFO 队列来管理多线程的排队工作。在公平竞争的情况下,无法获取同步状态的线程将会被封装成一个节点,置于队列尾部。入队的线程将会通过自旋的方式获取同步状态,若在有限次的尝试后,仍未获取成功,线程则会被阻塞住。
在同步队列中,头结点是获取了同步状态的节点。其他节点在尝试获取同步状态失败后,会被阻塞住,暂停运行。当头结点释放同步状态后,会唤醒其后继节点。后继节点会将自己设为头节点,并将原头节点从队列中移除。大致示意图如下: