锁分析
Lock
NonReentrantLock
ReadLock 共享锁
ReentrantLock 重入锁 排他锁
sync.lock 返回值为void,表示如无异常发生都认为锁获取成功
FairSync.lock 公平锁
FairSync.tryAcquire
获取线程
获取线程重入次数
重入次数为0
是 也就是第一次获取锁
在队列头部(队列为空或者当前线程在队列头部)
获取锁 设置锁状态 重入次数
设置锁的独占线程
获取锁成功
否
当前线程是否是锁的独占线程
是
重入次数+1 成功获取锁
否
获取锁失败
NonfairSync.lock 非公平锁
NonfairSync.lock
按照假设当前线程是第一次获取锁来申请锁
成功
设置当前线程为锁的独占线程
失败
按照重入的方式获取锁
WriteLock 排他锁
CAS 存在ABA的问题
ReentrantLock 重入锁默认构造是非公平锁实现,当申请锁的线程刚好碰到正在执行的线程释放了锁,那么他就有机会直接获取到锁,而不用排队。
重入锁的公平锁实现原理:
如果当前线程第一次获取锁,如果当前线程在抽象队列同步执行器的队首位置,利用CAS原理修改线程重入次数为1,成功则修改锁的独占线程为当前线程。
如果当前线程不是第一次获取锁,那么判断当前锁的独占线程与当前获取锁的线程是否一致,如果一致那么获取锁成功。
重入锁的非公平锁实现原理:
尝试按照第一次获取锁的方式直接获取锁,成功则获取锁成功
失败则重入的方式获取锁(判断当前线程与锁的独占锁是否一致)
Lock本地锁应用场景
根据锁创建的位置可以分为,对象锁,全局锁
1、对象锁,对象持有锁,在并发访问对象资源时可以用该锁控制。
public class ObjectLock {
private Lock objectLock = new ReentrantLock();
void objectLock(Ticket ticket) {
objectLock.lock();
try {
System.out.println(Thread.currentThread().getName()+":"+ticket.getNum());
ticket.setNum(ticket.getNum()+1);
Thread.sleep(1000);
} catch (Exception e) {
Console.error(e);
} finally {
objectLock.unlock();
}
}
}
2、全局锁,创建一个静态常量的锁,在系统全局都可以使用该锁。
public interface LockConstant {
Lock lock = new ReentrantLock();
}
void lockConstant(Ticket ticket) {
Lock lock = LockConstant.lock;
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+":"+ticket.getNum());
ticket.setNum(ticket.getNum()+1);
Thread.sleep(100);
} catch (Exception e) {
Console.error(e);
} finally {
lock.unlock();
}
}