并发安全性Lock锁及原理分析
文章目录
以下是学习中的一些笔记记录,如果有错误希望得到你的指正~ 同时也希望对你有点帮助~
ReentrantLock
- 重入锁、互斥锁
- 满足线程的互斥性,意味着同一时刻,只允许一个线程进入到加锁的代码中
public class ReentrantLockTest {
static int var = 0;
static Lock lock = new ReentrantLock();
public static void main(String[] args) {
Thread one = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
inc();
}
}, "Thread-One");
Thread two = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
inc();
}
}, "Thread-Two");
one.start();
two.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(var);
}
static void inc(){
lock.lock();
var++;
lock.unlock();
}
}
ReentrantLock
实现原理图
当
ThreadA
线程调用lock()方法去尝试抢占锁,如果AQS
中当前state状态为0,那么会使用CAS
去修改AQS
中state的值,并且exclusiveOwnerThread
指向当前持有锁的线程。当ThreadB
线程也去调用lock()方法尝试抢占锁时,发现此时AQS
中state != 0,ThreadB
将会封装成一个Node节点,并构建成一个双向链表进行排队等待,当ThreadA
线程执行完毕,调用unlock()方法释放锁,将会唤醒AQS
队列中head节点的下一个线程节点,锁的公平性与非公平性体现在释放锁的临界点,ThreadC
线程抢占到了lock锁,在ThreadB
线程抢到锁之前获得了锁
AbstractQueuedSynchronizer
在AQS
中实现了共享锁和互斥锁
- 共享锁
- 互斥锁
- state 互斥量 0 和 >0,0表示无锁状态,state()状态的获取和修改
exclusiveOwnerThread
指向持有锁的线程acquire(int arg)
争抢锁的定义tryAcquire(int acquires)
争抢锁定义,具体争抢锁逻辑由子类实现,例如NonfairSync
、FairSync
- 线程Node节点的封装,阻塞线程节点实现
Lock.lock()
公平锁lock()实现
static final class FairSync extends Sync {
final void lock() {
//尝试争抢一把锁
acquire(1);
}
//implement AbstractQueuedSynchronizer tryAcquire()
protected final boolean tryAcquire(int acquires) {
//记录当前争抢锁的线程
final Thread current = Thread.currentThread();
//获取当前AQS中的互斥量状态
int c = getState();
//无锁
if (c == 0) {
//公平锁上来就会判断AQS中是否存在线程节点排队,如果没有线程节点排队,接着尝试使用CAS去修改state值,修改成功表示抢占锁成功返回true
if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
//设置锁持有线程
setExclusiveOwnerThread(current);
return true;
}
//有锁再判断是否持有锁的线程是否是当前线程,重入
} else if (current == getExclusiveOwnerThread()) {
//这里互斥量的修改不需要使用CAS,因为当前线程已持有锁
int nextc = c + acquires;
if (nextc < 0) {
throw new Error("Maximum lock count exceeded");
}
//修改互斥量,重入次数
setState(nextc);
return true;
}
//抢占锁失败,并不是持有锁线程,返回false
return false;
}
}
非公平锁lock()实现
static final class NonfairSync extends Sync {
final void lock() {
//非公平锁一上来就会去争抢一次锁
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
} else {
//没有争抢到锁,再尝试争抢锁
acquire(1);
}
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//无锁
if (c == 0) {
//再次尝试抢占锁
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) {
//重入
int nextc = c + acquires;
if (nextc < 0) { // overflow
throw new Error("Maximum lock count exceeded");
}
//同步state
setState(nextc);
return true;
}
return false;
}
}
公共逻辑
class AbstractQueuedSynchronizer {
public final void acquire(int arg) {
//抢占锁失败,接着执行
//addWaiter(Node.EXCLUSIVE) 封装当前线程为一个Node节点,并构建为一个双向链表
//acquireQueued(addWaiter(Node.EXCLUSIVE), arg) 尝试争抢锁成功返回false,线程节点排队阻塞返回 true
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {
//中断当前阻塞的线程
selfInterrupt();
}
}
private Node addWaiter(Node mode) {
//将当前线程封装为Node节点
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
//当已经有线程节点排队的时候,tail节点此时为上一个线程节点
if (pred != null) {
//将当前线程节点指向上一个排队的线程节点
node.prev = pred;
//通过CAS将尾节点设置为当前线程节点,pred是上一个尾节点
if (compareAndSetTail(pred, node)) {
//上一个尾节点指向当前线程节点构成双向链表
pred.next = node;
//返回当前线程节点,也是排队的尾节点
return node;
}
}
//自旋处理构建线程节点
enq(node);
return node;
}
/**
* 构建一个头节点和尾节点相互指向的双向链表
* ----->
* head (new Node) 封装的线程节点(tail)
* <-----
*/
private Node enq(final Node node) {
for (;;) {
//首次为null,第二次为初始化的head节点
Node t = tail;
if (t == null) { // Must initialize
//通过CAS初始化一个head节点
if (compareAndSetHead(new Node()))
tail = head;
} else {
//
node.prev = t;
//通过CAS将线程节点设置为 tail节点
if (compareAndSetTail(t, node)) {
//head的next为线程节点
t.next = node;
return t;
}
}
}
}
/**
* @param node 当前线程封装后的节点
* @param arg 1
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//获取当前线程节点的上一个节点
final Node p = node.predecessor();
//如果上一个节点是head节点,再次尝试抢占锁,抢占锁成功则返回 interrupted
if (p == head && tryAcquire(arg)) {
//设置当前线程节点为head节点
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//不止一个线程节点排队,阻塞当前线程节点
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) {
interrupted = true;
}
}
} finally {
if (failed) {
cancelAcquire(node);
}
}
}
//通过LockSupport.park()阻塞抢占锁失败的线程
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
//中断当前的被阻塞的线程
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
}
Lock.unlock()
class ReentrantLock {
public void unlock() {
//释放一把锁
sync.release(1);
}
class Sync{
protected final boolean tryRelease(int releases) {
//获取互斥量state - 1
int c = getState() - releases;
//必须由持有锁的线程来释放锁
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException();
}
boolean free = false;
if (c == 0) {
free = true;
//清空,没有线程持有锁
setExclusiveOwnerThread(null);
}
//更改互斥量 state
setState(c);
return free;
}
}
}
class AbstractQueuedSynchronizer{
public final boolean release(int arg) {
//tryRelease 正常释放锁 返回true
if (tryRelease(arg)) {
//获取AQS队列head节点
Node h = head;
//head节点不为空
if (h != null && h.waitStatus != 0) {
//调用unpark方法进行唤醒
unparkSuccessor(h);
}
return true;
}
return false;
}
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
//在互斥锁中,ws小于0表示节点是可唤醒状态也就是SIGNAL状态的线程节点
if (ws < 0) {
//0默认状态,表示不属于AQS中定义的任何状态
compareAndSetWaitStatus(node, ws, 0);
}
Node s = node.next;
//ws大于0也就是CANCELLED状态,表示线程已经被销毁了,或者线程异常
if (s == null || s.waitStatus > 0) {
s = null;
//移除AQS队列中的ws>0的线程节点
for (Node t = tail; t != null && t != node; t = t.prev) {
//重新指向可唤醒的线程节点
if (t.waitStatus <= 0) {
s = t;
}
}
}
//唤醒封装在s节点中的Thread线程
if (s != null) {
LockSupport.unpark(s.thread);
}
}
}