ReentrantLock原理

实现了Lock接口
内部也维护了一个同步器Sync继承自AQS,Sync是抽象的,两个实现NonFairSync和FairSync

public ReentrantLock() {
    sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

非公平锁加锁解锁流程

// 加锁
CAS修改State状态0->1
修改成功,则将Owner线程设置为当前线程
修改失败
调用AQS中的acquire方法
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&  // 再次尝试获取锁
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
获取失败,addWaiter将当前线程封装为一个Node对象,加入到等待的双向Node链表中
进入acquireQueued逻辑
acquireQueued会在一个死循环中不断尝试获得锁,失败后park阻塞
1.如果是紧邻着head(head指向的Node节点的下一个Node节点),那么可以再次tryAcquire尝试获取锁,当然这时state仍为1,失败
2.进入shouldParkAfterFailedAcquire逻辑,将前驱node,即head的waitStatus改为-1,这次返回false
3.当再次进入shouldParkAfterFailedAcquire时,这时因为其前驱node的waitStatus已经是-1,这次返回true
4.进入parkAndCheckInterrupt,阻塞

在这里插入图片描述
在这里插入图片描述

// 解锁
调用了AQS的release方法
public final boolean release(int arg) {
	// tryRelease中将OwnerThread设置为null,将state设置为0
    if (tryRelease(arg)) { // 调用ReentrantLock中Sync内部类的tryRelease方法
        Node h = head;	// 看head的指向是否为null以及waitstatus
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h); // 找到等待链表中离head最近的一个Node(没取消的),unpark恢复其运行
        return true;
    }
    return false;
}
// 线程被唤醒后
final boolean acquireQueued(final Node node, int arg) {
    boolean interrupted = false;
	for (;;) {
	    final Node p = node.predecessor();
	    if (p == head && tryAcquire(arg)) { // 唤醒后恢复运行拿到锁
	        setHead(node); // 将head指向为自己的Node节点,自己的Node节点也不再关联线程
	        p.next = null; // help GC,将之前head指向的Node节点断开
	        return interrupted;
	    }
	    if (shouldParkAfterFailedAcquire(p, node))
	        interrupted |= parkAndCheckInterrupt(); // 获取锁时,是在这里被park阻塞的,所以也从这里恢复运行
	}
}

在这里插入图片描述
非公平锁,当释放锁的时候,又来了一个线程,会和刚被唤醒的线程竞争
被唤醒的线程没竞争过,则又会park,去睡觉

可重入原理

获取锁时,如果state已经为1,会判断当前线程是不是Owner线程
如果是,表示发生了锁重入,会让state++
释放锁时调用tryRelease方法,会让state减1,减完之后发现不是0,则返回false,不会释放锁
只有当state减完之后变为0了,才会释放锁,返回true

可打断原理

默认是不可打断的,因为被打断后恢复运行,会继续尝试获得锁,获得到会将打断标记true作为结果返回,获得不到会继续阻塞

final boolean acquireQueued(final Node node, int arg) {
	boolean interrupted = false;
	for (;;) {
		final Node p = node.predecessor();
		if (p == head && tryAcquire(arg)) {
			setHead(node);
			p.next = null; // help GC
			return interrupted; // 获取锁时,会将打断标记作为结果返回
		}
		if (shouldParkAfterFailedAcquire(p, node))
			// 被打断唤醒后会将打断标记清除(为了下面获取锁失败时还可以park住),将true赋给interrupted
			interrupted |= parkAndCheckInterrupt();
	}
}
// 这里acquireQueued返回true,表示是被打断后恢复运行拿到了锁
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        // 这里会重新设置打断标记,因为之前清理了打断标记
        selfInterrupt();
}

可打断(使用另一个获取锁的方法),打断唤醒后,会直接抛出异常,不会再尝试获取锁

公平锁原理

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
    	// 竞争锁之前先判断等待链表中的情况
        if (!hasQueuedPredecessors() &&
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 判断当前线程是不是Owner线程
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}
// java.util.concurrent.locks.AbstractQueuedSynchronizer#hasQueuedPredecessors
public final boolean hasQueuedPredecessors() {
    Node h, s;
    if ((h = head) != null) { // head是否为null
        if ((s = h.next) == null || s.waitStatus > 0) {
            s = null; // traverse in case of concurrent cancellation
            for (Node p = tail; p != h && p != null; p = p.prev) {
                if (p.waitStatus <= 0)
                    s = p;
            }
        }
        // 如果有head指向的Node节点的下一个Node节点,且关联的线程不是自己
        // 则自己就不要去竞争锁了
        if (s != null && s.thread != Thread.currentThread())
            return true;
    }
    return false;
}

条件变量实现原理

每个条件变量对应着一个等待链表,实现类是ConditionObject,维护了一个双向链表
await流程

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();// 创建Node对象,添加到等待链表中.Adds a new waiter to wait queue.
    long savedState = fullyRelease(node);// 释放锁,唤醒AQS等待链表中的一个Node节点
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this); // 阻塞住
    }
}

在这里插入图片描述
在这里插入图片描述
signal流程
先检查当前线程是不是锁的持有者,不是则抛出异常
将ConditionObject维护的等待链表中的第一个Node节点移除,转移到AQS的等待链表中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值