手写非公平锁(ReentrantLock)

​ ReentrantLock很多教程都在讲解,虽然很细致,但内容太多了,过段时间就很容易忘,我们知道ReentrantLock的核心是AQS(抽象队列同步器),我们这里试着使用AQS,自己写一个非公平锁使用,看看AQS承载了哪部分的职责,ReentrantLock承载了哪部分的职责

第一步:定义接口,面向接口编程嘛

public interface myLock {
  	// 很简单的加锁和释放锁
    public void lock();
    public void unlock();
}

第二步:看看ReentrantLock与AQS的关系

public class myUnFairLock implements myLock {

    private final Sync sync = new Sync();

  	// 锁的核心由AQS管理,ReentrantLock只负责重写 tryAcquire 和 tryRelease方法的逻辑
  	private static class Sync extends AbstractQueuedSynchronizer {
      	@Override
        protected boolean tryAcquire(int arg) {}
       	@Override
        protected boolean tryRelease(int arg) {}
      
      	public void lock() {
          	// 这些方法AQS都已经封装好,我们只需要组合即可
          	if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
            } else {
                acquire(1);
            }
        }
      
      	public void unlock(release(1);)
    }
  
    @Override
    public void lock() {
        sync.lock();
    }

    @Override
    public void unlock() {
        sync.unlock();
    }
}

第三部:查看ReentrantLock重写的加锁,释放锁的步骤

private static class Sync extends AbstractQueuedSynchronizer {
    @Override
    protected boolean tryAcquire(int arg) {
        // 获取当前线程
        final Thread current = Thread.currentThread();
        // 获取同步器的状态值(AQS初始好的),其实就是一个锁的引用计数器,为0时表示锁无人占有
        int state = getState();
        // 说明state值是与锁状态有关的
        if (state == 0) {
            // 0代表可以再次抢锁
            if (compareAndSetState(0, arg)) {
                // 如果抢到,指明当前线程,获取到锁了
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        // 判断占有线程是否就是自己,保证锁的可重入性
        else if (current == getExclusiveOwnerThread()) {
            // 如果是自己的锁,则计数器+1
            int newState = state + arg;
            // 这里是怕无限递归,造成计数器溢出
            if (newState < 0) {
                throw new Error("Maximum lock count exceeded");
            }
            // 设置新的值
            setState(newState);
            return true;
        }
        return false;
    }

    @Override
    protected boolean tryRelease(int arg) {
        // 获取锁的引用计数器
        int c = getState() - arg;
        // 判断清楚现在释放的锁是自己占用的锁不
        if (Thread.currentThread() != getExclusiveOwnerThread()) {
            throw new IllegalMonitorStateException();
        }
        boolean free = false;
        if (c == 0) {
            // 锁状态清0
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        // 如果锁还有被引用,就是false,无引用就是true
        return free;
    }

    public void lock() {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
        } else {
            acquire(1);
        }
    }

    public void unlock() {
        release(1);
    }
}

​ 这些就是ReentrantLock核心做的事儿,其他的都交给AQS来完成,例如设置锁占有,获取锁值,通过原子比较尝试获取锁,阻塞线程的管理等。如果需要我们可以在中间加入我们的逻辑,来替代原有的ReentrantLock。