AQS ReentrantLock源码实现

AQS ReentrantLock

从ReentrantLock构造方法开始看

public ReentrantLock() {
        sync = new NonfairSync();
    }

默认的构造方式是非公平方式实现(公平非公平就是是不是按线程顺序执行),aqs的锁机制由sync类控制,sync继承了AbstractQueuedSynchronizer,AbstractQueuedSynchronizer继承了AbstractQueuedSynchronizer,aqs里有一个静态final类叫Node,包装线程为一个对象,后期所有的操作都是基于node实现的,
node类中需要关注的属性
volatile Node prev; 前一个节点
volatile Node next; 下一个节点
volatile Thread thread;当前线程
volatile int waitStatus;等待的状态 关注0和-1就可以
static final Node EXCLUSIVE = null; 独占
aqs类中需要关注的属性
private transient volatile Node head;头结点
private transient volatile Node tail;尾节点
private volatile int state;状态

那我们就从非公平的lock方法开始看

 static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
        //当非公平方法
        final void lock() {
        	//这里使用unsafe的cas把0改为1就算获取成功了,设置当前线程独占
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
            //如果有多个线程并发获取,肯定有人失败就进入下面的方法
                acquire(1);
        }
    }

acquire传入1代表我要获取这把锁,这里又有四个方法一个一个看

 public final void acquire(int arg) {
 		//tryAcquire判断当前线程是否占有锁,占有就为true
 		//如果尝试获取锁失败了就继续进入addWaiter方法,传入Node.EXCLUSIVE,没有初始化所以是null
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            //如果获取锁成功,就挂起当前线程,等待唤醒
            selfInterrupt();
            /*
             static void selfInterrupt() {
               Thread.currentThread().interrupt();
               }
    }
            */
    }

第一个方法tryAcquire,传入状态1

 final boolean nonfairTryAcquire(int acquires) {
 			//设置为当前线程
            final Thread current = Thread.currentThread();
            //获取当前的state,由于未初始化默认为0
            int c = getState();
            //无锁,任何人都可进来设置,如果是公平锁则会判断当前节点是否有前一个节点,如果有就等前一个释放
            if (c == 0) {
            	//cas将状态0改为1,改成功则独占锁,否则返回false
                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  看到这就知道为啥叫重入锁了,
                //还有为啥lock几次就得unlock几次 ,lock一次state+1 unlock-1 只有为0其他线程才能重新cas把state改为1
                setState(nextc);
                return true;
            }
            return false;
        }

第二个方法addWaiter,加入等待队列尾部(修改前后引用),争抢设置

 private Node addWaiter(Node mode) {
 		// 包装了一个node,传入当前线程,和一个null
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        //tail 和 pred 刚new出来都是空,设置node节点的前一个节点为null
        if (pred != null) {
            //不是空就有尾节点,将尾节点放到自己前面,自己是最后一个
            //我的脑袋是你
            node.prev = pred;
            //cas如果能将tail设置为node
            if (compareAndSetTail(pred, node)) {
                //那么就将尾节点的下一个节点设置为node
                //你的尾巴是我
                pred.next = node;
                return node;
            }
        }
        //为空就要看神奇的enq方法了
        enq(node);
        return node;
    }

enq方法,首先捋一下,想要进入这个方法,那么是尾节点是空的情况(等待列表空),或compareAndSetTail cas失败,并发的设置头结点

 private Node enq(final Node node) {
        for (;;) {        	
            Node t = tail;
            //尾节点如果是空
            if (t == null) { // Must initialize
            	//cas谁能把当前类null改为 new node
                if (compareAndSetHead(new Node()))
                   //这里tail = 刚刚new的node,然后再次循环
                   tail = head;
            } else {
            	//加入尾部
                node.prev = t;
                //cas将尾节点改为当前线程的node
                if (compareAndSetTail(t, node)) {
                	//如果cas成功了,就将new出的节点的后一个节点改为当前线程的节点
                    t.next = node;
                    return t;
                }
            }
        }
    }

第三个方法acquireQueued,传入刚才返回的node,和1,这个方法就是不断的循环,直到当前线程的前一个节点和head相同,就返回

  final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
        	//中断状态
            boolean interrupted = false;
            for (;;) {
            	//检查当前线程的前一个节点是否是null,正常就是刚new出来的head
                final Node p = node.predecessor();
                //看看自己的前一个节点是不是head,
                //如果是当前线程就是等待队列中第一个要执行的,然后去尝试获取锁
                if (p == head && tryAcquire(arg)) {
                	//将head改为当前线程的node
                    setHead(node);
                    //可达性分析,断开尾部引用
                    p.next = null; // help GC
                    failed = false;
                    //return之前执行finally
                    return interrupted;
                }
                //如果不是传入当前线程前一个节点,和自己,这里cas改waitStatus失败后会重新循环
                if (shouldParkAfterFailedAcquire(p, node) 
                
                //如果改成功了 加锁,当前线程挂起等待唤醒
                /*
                 private final boolean parkAndCheckInterrupt() {
                 LockSupport.park(this)
                 //唤醒当前线程
                 return Thread.interrupted();
                 }
                */
                    &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

shouldParkAfterFailedAcquire

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
		//初始化为0
        int ws = pred.waitStatus;
        //waitStatus为-1 就可以正常返回
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
            	//每次将自己的前节点设置为pred
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
             //cas 将pred的waitStatus改为-1
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
      
        return false;
    }

unlock方法

 public final boolean release(int arg) {
 		//当state = 0的时候
        if (tryRelease(arg)) {
            Node h = head;
            //头结点不是空,并且等待标识不是0,也就是不是初始状态
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

尝试释放锁

protected final boolean tryRelease(int releases) {
			//获取过锁且没有重入过就是1,重入过>1
            int c = getState() - releases;
            //当前线程 如果不是当前独占的线程,就是没在锁定状态的话
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();    
            boolean free = false;
            //当stat
            if (c == 0) {
                free = true;
                //重置独占锁线程坑,其他线程可以去竞争了
                setExclusiveOwnerThread(null);
            }
            //每调用一次unlock就 -1 直到为0才能取消独占
            setState(c);
            return free;
        }

unparkSuccessor方法

private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
        if (ws < 0)
        	//头节点如果waitStatus小于0证明还在占用用,cas尝试改为0
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        Node s = node.next;
        //头结点的下一个节点是空
        if (s == null || s.waitStatus > 0) {
            s = null;
            // 尾节点不为空并且不是头结点 就向前设置
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                        s = t;
        }
        if (s != null)
            //唤醒后面的节点
            LockSupport.unpark(s.thread);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容越多,也需要更多的人来对数据进行整理,并且数据的汇总查询方面效率也是极其的低下,并且数据安全方面永远不会保证安全性能。结合数据内容管理的种种缺点,在互联网时代都可以得到有效的补充。结合先进的互联网技术,开发符合需求的软件,让数据内容管理不管是从录入的及时性,查看的及时性还是汇总分析的及时性,都能让正确率达到最高,管理更加的科学和便捷。本次开发的高校科研信息管理系统实现了操作日志管理、字典管理、反馈管理、公告管理、科研成果管理、科研项目管理、通知管理、学术活动管理、学院部门管理、科研人员管理、管理员管理等功能。系统用到了关系型数据库中王者MySql作为系统的数据库,有效的对数据进行安全的存储,有效的备份,对数据可靠性方面得到了保证。并且程序也具备程序需求的所有功能,使得操作性还是安全性都大大提高,让高校科研信息管理系统更能从理念走到现实,确确实实的让人们提升信息处理效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值