『每日一问』ReentrantLock加锁解锁

在这里插入图片描述
ReentrantLock 、Sync 、FairSync 、NonfairSync 代码之间的组织关系

public class ReentrantLock{
	abstract static class Sync extends AbstractQueuedSynchronizer{
		//...
	}
	static final class NonfairSync extends Sync {
		//...
	}
	static final class FairSync extends Sync{
		//...
	}
}

Lock接口中定义了六个方法

//加锁
void lock();
//可中断的加锁
void lockInterruptibly() throws InterruptedException;
Condition newCondition();
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//解锁
void unlock();
加锁
ReentrantLock.lock
	public void lock() {
	    sync.lock();
	}
	//这个sync是ReentrantLock中的一个属性
	private final Sync sync;
	//因为Sync是abstract修饰的,那么这里的Sync是哪一个子类呢?
	//看构造方法,默认就是一个非公平锁
	public ReentrantLock() {
        sync = new NonfairSync();
    }
    //当然,是否公平锁是可以指定的
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
NonfairSync.lock
   @Override
   final void lock() {
       if (compareAndSetState(0, 1)) {
           setExclusiveOwnerThread(Thread.currentThread());
       } else {
           acquire(1);
       }
   }
	
	//首先呢你看到了@Override,那么没错这个lock()就是Sync中的一个抽象方法
	abstract void lock();

再来一步步看实现

1. CAS设置锁状态state的值
	/**
     * 如果当前状态值等于预期值,则自动将同步状态设置为给定的更新值。
	 * 该操作具有{@code volatile}读写的内存语义。
     *
     * @param expect 期待值,也就是你预想的旧值
     * @param update 新的值
     * @return {@code true} if successful. 返回false表示实际值与预期值不相等。
     */
    protected final boolean compareAndSetState(int expect, int update) {
        //unsafe的操作是native操作
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
2. 如果当前线程设置锁状态成功,说明当前线程获取锁成功,那么设置当前线程为持有锁的线程
	/**
	 * 这个方法是AbstractOwnableSynchronizer中的
	 * 		AbstractOwnableSynchronizer是AbstractQueuedSynchronizer的抽象父类,
	 * 里边维护了一个代表当前单独访问的线程引用
	 * 		private transient Thread exclusiveOwnerThread;
	 * 
	 */
	protected final void setExclusiveOwnerThread(Thread thread) {
        exclusiveOwnerThread = thread;
    }
3. 如果当前线程没有成功设置state的状态
	1.尝试再次获取锁,期间要是发现加锁的线程就是当前线程,state++,也就是支持可重入
	2.尝试失败,当前线程创建Node节点,然后以 『CAS + 死循环』 的方式保证放到等待队列中,同时设置当前节点为尾节点 , 
		节点进入同步队列之后,就进入了一个 『自旋』 的过程,每个节点(或者说每个线程)都在自省地观察,
		当条件满足,获取到了同步状态,就可以从这个自旋过程中退出,否则依旧留在这个自旋过程中(并会阻塞节点的线程)
    /**
	 * 这个方法是AbstractOwnableSynchronizer中的
	 * 实现的效果就是
	 * 		如果(尝试获取锁失败 并且 将当前线程加阻塞队列成功){
	 * 			将当前线程中断
	 * 		}
	 */
    public final void acquire(int arg) {
        if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt(); //Thread.currentThread().interrupt();
    }
    //3.1、tryAcquire(arg);
    /**
	 * 这个方法最终到了nonfairTryAcquire这个方法
	 * 
	 */
	 final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
           	//获取当前锁的状态
            int c = getState();
            //如果是无锁状态,也就是state为0
            if (c == 0) {
            	//CAS设置锁状态为1,设置成功后设置当前锁的持有线程
                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累加,这里就可以发现,Reentrant是可重入的
                setState(nextc);
                return true;
            }
            //如果是有锁状态 且 锁的持有线程不是当前线程,直接返回false,也就是线程尝试获取锁失败
            return false;
     }
     /**
     * 3.2、addWaiter(Node mode)
     * 为当前线程和给定模式创建和排队节点。
     * @param mode Node.EXCLUSIVE for exclusive(独占), Node.SHARED for shared(共享)
     * @return 新的节点
     */
    private Node addWaiter(Node mode) {
    	//创建一个新的node
        Node node = new Node(Thread.currentThread(), mode);
        /**
         * 获取尾部节点
         * AQS中有两个成员变量,用来表示等待队列中的头部以及尾部节点
         * private transient volatile Node head;
         * private transient volatile Node tail;
         */
        Node pred = tail;
        if (pred != null) {
        	//设置新节点的头结点指向原先队列的尾部节点
            node.prev = pred;
            //CAS设置尾节点,保证安全性
            if (compareAndSetTail(pred, node)) {
            	//新节点的next节点指向自己
                pred.next = node;
                return node;
            }
        }
        //前边的CAS可能会失败,这里通过一个死循环来保证设置尾节点一定成功
        enq(node);
        return node;
    }
     private Node enq(final Node node) {
        /**
         * 同步器通过“死循环”来保证节点的正确添加,在“死循环”中只有通过CAS将节点设置成为尾节点之后,当前线程才能从该方法返回,
         * 否则,当前线程不断地尝试设置。可以看出,enq(final Node node)方法将并发添加节点的请求通过CAS变得“串行化”了。
         */
        for (; ; ) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
     }
      /**
     * 3.3、acquireQueued(final Node node, int arg)
     *	
     */
     final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (; ; ) {
                final Node p = node.predecessor(); //就是node.prev
                if (p == head && tryAcquire(arg)) {//只有node.prev是头部节点,才可以去尝试获取锁,也满足了队列的FIFO原则
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
解锁
ReentrantLock.unlock()
	@Override
    public void unlock() {
    	//每次解锁相当于state-=1 , 因为可重入的特性,state会大于1
        sync.release(1);
    }

	//AbstractQueuedSynchronizer.release
	public final boolean release(int arg) {
        if (tryRelease(arg)) {
        	//因为ReentrantLock是支持可重入的,这里只有持有锁的线程释放掉所有的state,
        	//也就是state一直减到0为止,tryRelease才会返回true
            Node h = head;
            if (h != null && h.waitStatus != 0)
                //唤醒下一个节点
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

	//Sync.tryRelease
	/**
	 * state是volatile修饰的一个单一变量,在具有可见性的基础上就具有了原子性
	 */
	@Override
    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        //如果当前解锁的线程不是锁的持有线程,抛出异常
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;//标记当前线程是否完全释放锁,也就是state减为0
        if (c == 0) {
        	//state为0,是当前线程完全释放锁标记唯一条件
            free = true;
            //设置当前锁持有线程为null
            setExclusiveOwnerThread(null);
        }
        //回写state
        setState(c);
        return free;
    }
    protected final void setState(int newState) {
        state = newState;
    }

注意:

  • 独占式锁中,线程因为获取同步状态失败之后进入同步队列中,后续对线程进行中断操作时,线程不会从同步队列中移出
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值