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

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

基于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;


public class ExclusiveLock implements Lock {

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

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

        
        @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;
        }

        
        @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 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);
    }

    
    @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{
    // 号令q,确保同时争抢锁,之前文档有做说明
    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;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5563566.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存