AbstractQueuedSynchronizer学习

有两种队列,都是非阻塞式队列

  • 同步队列(FIFO队列)
  • 条件队列
    都共用了节点ADT

非阻塞队列与阻塞队列比较

  • 队列遵循先进先出,后进后出的原则。
  • 阻塞式队列比非阻塞式队列性好。

区别:
阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完全清空队列

线程的阻塞与解除阻塞
利用LockSupport.park() 和 LockSupport.unpark() 实现线程的阻塞和唤醒(底层调用Unsafe的native park和unpark实现),同时支持超时时间。
在这里插入图片描述
AQS 里将阻塞线程封装到一个内部类 Node 里。并维护一个 CLH Node FIFO 队列。 CLH队列是一个非阻塞的 FIFO 队列,往里面插入或移除一个节点的时候,在并发条件下不会阻塞,而是通过自旋锁和 CAS 保证节点插入和移除的原子性。
参数

		//表示共享
		static final Node SHARED = new Node();
       //表示独占
        static final Node EXCLUSIVE = null;
		//当前节点线程被取消
        static final int CANCELLED =  1;
       //当前节点的后继节点的线程在等待锁
        static final int SIGNAL    = -1;
        //当前节点时条件队列的节点
        static final int CONDITION = -2;
       //表示应该无条件传播,失败主动取消会设置这个类型
        static final int PROPAGATE = -3;
        //标识状态,取上面几个int类型的值
        volatile int waitStatus;
        //当前节点的前驱
        volatile Node prev;
        //当前节点的后继
        volatile Node next;
        //当前节点属于的线程
        volatile Thread thread;
        //如果是条件队列,就指向下一个节点,否则被赋值成shared的static final Node SHARED = new Node();
		Node nextWaiter;

独占模式下acquire函数

  • 修改当前锁的状态state
  • 设置持有锁的线程

共享模式下acquire函数

  • 共享锁可以被多个线程同时拿到,具体同步器的实现类,是否允许,看每个同步器自己的实现。
  • 节点的waitStatus设置为SHARED
  • 只修改state字段,不设置持有锁的线程

acquire操作

  1. 入队
  2. 申请入队

独占模式下release函数
操作,释放锁

  • 检查当前线程是否和持有锁的线程是同一个线程
  • 修改锁的状态,state字段
  • 唤醒队到中头节点的下一个节点的线程

唤醒的动作:

  • 将自己的waitStatus设成0
  • 真正的叫起线程

头结点的下一个节点

  • 检查自己的前驱节点是不是头节点
  • 争用锁

共享模式下release函数

  • 修改锁状态,修改state字段
  • 唤醒队列中头节点的下一个节点的线程
  • 取当前被唤醒的节点的下一个节点,如果下一个节点也是SHARED模式,则直接唤醒

条件队列

await操作
1,创建条件节点,必要的时候初始化条件队列或者把自己加入到条件队列中
2,释放当前线程占有的锁,执行AQS release操作
3,挂起当前线程
4,被唤醒以后,执行AQS acquire入队列的第二步操作:申请入队列

signal操作
1,条件队列中的节点(firstWaiter)转移到同步队列中
2,把刚刚加入到同步队列中的条件节点的前驱的waitStatue =-1(当前节点的后继节点的线程在等待锁)

独占模式代表ReentrantLock

nonfairTryAcquire函数

final boolean nonfairTryAcquire(int acquires) {
			//current:获取当前线程
            final Thread current = Thread.currentThread();
            int c = getState();
            //无锁状态
            if (c == 0) {
            	//设置state,设置持有锁的线程,返回true
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            	//判断当前线程和持有锁的线程是否是同一个线程,不是直接返回false,争取资源失败
            else if (current == getExclusiveOwnerThread()) {
            	//这里就是可重入的逻辑,lock几次就加几次
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

addWaiter函数

//返回当前创建的节点
private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        //未初始化队列,先初始化队列,enq函数返回的是前驱节点
        enq(node);
        return node;
    }

acquireQueued函数

final boolean acquireQueued(final Node node, int arg) {
		//标记是否成功拿到资源
        boolean failed = true;
        try {
        	//标记等待过程中是否被中断过
            boolean interrupted = false;
            //自旋
            for (;;) {
            	//p:当前节点的前驱结点
                final Node p = node.predecessor();
                //如果前驱是头结点会有一次额外机会争用锁(比如刚把队列构造好,还未真正入队列)
                if (p == head && tryAcquire(arg)) {
                	//当前节点设置为头节点
                    setHead(node);
                    //为了回收
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                //第一个条件:true:当前节点等待被唤醒,若为false,表示当前节点刚挂上来,又从上边开始执行,获得一次争取锁的机会
                //第二个条件:挂起当前线程
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

shouldParkAfterFailedAcquire函数

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        //如果为-1,表示后继节点等待被唤醒,直接返回true
        if (ws == Node.SIGNAL)          
            return true;
        if (ws > 0) {
           
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
          	//在默认为0的情况下,强制设置前驱节点状态为-1
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

release函数

public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            //第一个条件:同步队列存在
            //第二个条件,要唤醒后边的节点,自己的状态为-1
            if (h != null && h.waitStatus != 0)
            	//传入头结点,唤醒下一个节点
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease

protected final boolean tryRelease(int releases) {
			//当前状态-1
            int c = getState() - releases;
            //当前线程是否和持有锁的线程是同一个线程
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                //清除锁的要释放的线程信息
                setExclusiveOwnerThread(null);
            }
            //0
            setState(c);
            //状态为0,完全被释放(重入锁的可能性)
            return free;
        }

unparkSuccessor函数
唤醒等待队列中下一个线程

private void unparkSuccessor(Node node) {
      
        int ws = node.waitStatus;
        //true:需要唤醒下一个节点,且改自己状态为0
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);      
        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;
        }
        //唤醒操作,回到在acquireQueued被挂起操作执行死循环里边的东西去尝试获取锁,并不是一定获取锁,可能新入队列的也会去争取锁,这就是非公平的体现
        if (s != null)
            LockSupport.unpark(s.thread);
    }

公平的tryAcquire

protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
            		//第一个条件:false:当前节点前边还有节点,不能争取锁,保证了公平性
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

共享模式代表CountDownLatch

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值