基于AQS实现可重入的互斥锁(ReentrantLock的大致实现思想)

代码中有详细注释,这里不做说明了,解释一下涉及到的名词:

AQS:AbstractQueuedSynchronizer。是所有并发工具实现的框架基础。

可重入锁:自己可以重新获取自己当前获取的锁(比较绕口),不可重入的话自身会把自身锁死!

非公平锁:后来的线程可能先拿到锁,即拿到所的顺序是不公平的(这样反而性能更好)

互斥锁:只有一个线程能拿到锁,其他线程会被阻塞。

实现代码如下:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 基于AQS实现的互斥锁(可重入,非公平锁)
 */
public class ExclusiveLock implements Lock {

    // 生成同步器私有变量
    private final Sync sync = new Sync();

    // 静态内部类,同步器!继承AQS,是实现锁的核心
    private class Sync extends AbstractQueuedSynchronizer{

        /**
         * 获取锁 真正的实现方法
         * @param acquire
         * @return
         */
        @Override
        protected boolean tryAcquire(int acquire) {
            if (compareAndSetState(0,acquire)){ // CAS操作设置锁的状态,
                // 成功代表拿到锁,将当前线程设置为持有锁的线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true; // 拿到了锁
            }else if (getExclusiveOwnerThread() == Thread.currentThread()){ // 重入,判断拿到锁的是不是当前线程
                // 是,意味重入,锁的层级+acquire ;
                // 先判断 锁的状态是否 > 0,确保正常!否则提示超出锁计数。
                if (getState() + acquire < 0){
                    throw new Error("Maximum lock count exceeded!");
                }
                // 这里不用CAS是因为是单线程执行的(锁被单一线程持有),一定不会出现并发安全性问题
                setState(getState() + acquire);
                return true;
            }
            // 其余都是未拿到锁,尝试拿到锁失败。
            return false;
        }

        /**
         * 释放锁 真正的实现方法
         * @param acquire
         * @return true  释放锁成功
         *         false 释放锁失败,锁仍然被当前线程持有!
         */
        @Override
        protected boolean tryRelease(int acquire) {
            if (getExclusiveOwnerThread() != Thread.currentThread()){
                // 抛出该异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器,然而本身没有指定的监视器的线程。
                // 简单的说就是当前线程不是 对象监控器 的所有者
                throw new IllegalMonitorStateException();
            }else if (getState() ==  0){
                throw new IllegalMonitorStateException();
            }
            // 检查通过,锁的层级-- 不使用CAS操作原因同上
            setState(getState() - acquire);
            if (getState() == 0){
                // 锁的层级为0,代表失去锁的持有,将锁的持有线程设置为空
                setExclusiveOwnerThread(null);
                // 已经没有线程对锁持有,返回释放成功!
                return true;
            }
            // 正常执行到这里代表当前线程还持有对锁的持有,因此释放锁失败!
            return false;
        }

        //方法名直译:是否独占?(不用说了吧!)
        @Override
        protected boolean isHeldExclusively() {
            // 根据getState() 判断锁的状态
            return getState() > 0;
        }

        /* 返回一个Condition,每个Condition都包含了一个
         * condition 队列 */
        Condition newCondition(){
            return new ConditionObject();
        }
    }

    /**
     * 面向使用者的锁方法
     */
    @Override
    public void lock() {
        // System.out.println(提示1);
        sync.acquire(1);
        // System.out.println(提示2);或者写自己的逻辑.......
    }


    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    /**
     * 尝试获取锁
     * @return
     */
    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1,unit.toNanos(time));
    }

    /**
     * 释放锁
     */
    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }
}

测试:

public class LockTest{
    // 号令枪,确保同时争抢锁,之前文档有做说明
    private CountDownLatch countDownLatch = new CountDownLatch(1);
    private int count = 0;
    private final ExclusiveLock lock = new ExclusiveLock();

    private class Test extends Thread{

        @Override
        public void run() {
            try {
                countDownLatch.await();
                lock.lock();
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName());
                if (count < 3){
                    ++count;
                    System.out.println(System.currentTimeMillis()+"===="+count+"==="+Thread.currentThread().getName());
                }
                lock.unlock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) {
        LockTest lockTest = new LockTest();
        for (int i=0;i<10;i++){
            Test tt = lockTest.new Test();
            tt.start();
        }

        lockTest.countDownLatch.countDown();
    }
}

间隔一秒,说明资源被锁定了一段时间。

公平锁在实际中较少使用:

实现只需要把上面那个tryAcquire()中的逻辑稍微修改即可。

@Override
protected boolean tryAcquire(int acquire) {
    // 判断是否还有前驱节点,直接自己为头节点了或者同步队列空了才会继续后面的锁的获取操作
    if (!hasQueuedPredecessors() && compareAndSetState(0,acquire)){
        setExclusiveOwnerThread(Thread.currentThread());
        return true;
    }else if (getExclusiveOwnerThread() == Thread.currentThread()){
        if (getState() + acquire < 0){
            throw new Error("Maximum lock count exceeded!");
        }
        setState(getState() + acquire);
        return true;
    }
    return false;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值