ReentrantLock

   ReentrantLock : 可以创建  公平 or 非公平锁, 本问主要说非 公平锁

   知,lock, trylock,lockInterruptibly

      这里是架构图,太简单了 不补了

 ReentrantLock 内部主要类

    /**
     * 同步控制的基类.下边有两个子类:非公平和公平
     *.使用了AbstractQueuedSynchronizer类的的一些方法
     */
    static abstract class Sync extends AbstractQueuedSynchronizer

    /**
     * 非公平
     */
    final static class NonfairSync extends Sync

    /**
     * 公平
     */
    final static class FairSync extends Sync    

   2. 非公平锁的lock 过程

    final void lock() {
        if (compareAndSetState(0, 1)) // 我 插下队, 现在要是没有在用我就直接试一试
            setExclusiveOwnerThread(Thread.currentThread()); // 当前线程OK
        else
            acquire(1); //去得到锁 表示出阻塞了
    }
    public final void acquire(int arg) {
        if (!tryAcquire(arg) && // 尝试的去获取下
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))// 生成Node入队后在轮询等到他可以执行, 如果在这个过程中被中断那么, 当这个线程获得锁的时候出来后会返回true
            selfInterrupt();// 中断了我擦
    }  
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
         final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread(); 
            int c = getState();
            if (c == 0) {// 没人? 我要插队
                if (compareAndSetState(0, acquires)) {// 插队插队
                    setExclusiveOwnerThread(current);// 插队成功yes
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {// 本来就是锁的拥有者
                int nextc = c + acquires; // 可重入锁 标记下
                if (nextc < 0) // overflow 
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    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;// OK suc
                return node;
            }
        }
        enq(node);// 没办法入队 失败了,慢慢来
        return node;
    }
    private Node enq(final Node node) {
        for (;;) { 
Node t
= tail; if (t == null) { // 没有元素啊,那我初始化下 if (compareAndSetHead(new Node()))// cas替换下 tail = head; //OK 有头了我 重来下 } else { // 和一开始的入队 逻辑一样的
node.prev
= t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } } final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false;
       // 循环直到 本NODE成为 head成为可执行方式, 没被挂起前是自旋锁
for (;;) { final Node p = node.predecessor();
// 前一个节点是 head啊 那么 来吧我们尝试 着成为 拥有者, 因为存在插队情况 所以 会有try的字样。
          // 值得 一提的 是 如果  我被 unpark但是 又被别人抢了, 那我 就 会 自旋,在挂起
if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && // 捕获失败了是不是要挂起啊
parkAndCheckInterrupt()) // 挂起 成为重(重量的重)锁, 阻塞等待 unpark。并且检测 是否被中断? interrupted = true;              // 标记 } } finally { if (failed)// 失败 不可能的啊 cancelAcquire(node); } }

  1. CANCELLED,值为1,因为超时或者中断,结点会被设置为取消状态,被取消状态的结点不应该去竞争锁,只能保持取消状态不变,不能转换为其他状态。处于这种状态的结点会被踢出队列,被GC回收;
  2. SIGNAL,值为-1,表示这个结点的继任结点被阻塞了,到时需要通知(unpark)
  3. CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中
  4. PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执,使用在共享模式头结点有可能牌处于这种状态,表示锁的下一次获取可以无条件传播;
  5. 值为0,表示当前节点在sync队列中,等待着获取锁。新结点会处于这种状态。(获取不到缩就会被转换成 SIGNAL)
  
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; 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 { 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. */
// 从ws -> signal
compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; } private final boolean parkAndCheckInterrupt() { LockSupport.park(this);// 阻塞这个线程 unpark函数可以先于park调用,比如线程A调用unpark函数,给线程B发了一个“许可”,那么当线程B调用park时,它发现已经有“许可”了,那么它会马上再继续运行 而这是 wait notify 所做不到的 return Thread.interrupted(); // 清除中断标记, 并且返回 刚才被中断了么 }

 公平锁和 非公平的差不多, 只不过没有插队的 逻辑, 所以就不说了

 3. unlock过程

 

    public void unlock() {
        sync.release(1);
    }
    public final boolean release(int arg) {
        if (tryRelease(arg)) { // 尝试 释放
            Node h = head;  // 释放成功, 那么获取头部
            if (h != null && h.waitStatus != 0) // 存在 头节点 且 不是取消的哦状态
                unparkSuccessor(h); // 对 距离最近的 节点做唤醒操作。
            return true; // suc
        }
        return false; // what?
    }

 

        protected final boolean tryRelease(int releases) { // 释放
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread()) // 当前县城 没有锁啊 , 没有lock 就 unlock了
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) { // 锁都释放了我去
                free = true;
                setExclusiveOwnerThread(null); // 再见 
            }
        // 存在 重入 d setState(c);// 设置状态
return free; }
   
  1. CANCELLED,值为1,因为超时或者中断,结点会被设置为取消状态,被取消状态的结点不应该去竞争锁,只能保持取消状态不变,不能转换为其他状态。处于这种状态的结点会被踢出队列,被GC回收;
  2. SIGNAL,值为-1,表示这个结点的继任结点被阻塞了,到时需要通知(unpark)
  3. CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中
  4. PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执,使用在共享模式头结点有可能牌处于这种状态,表示锁的下一次获取可以无条件传播;
  5. 值为0,表示当前节点在sync队列中,等待着获取锁。新结点会处于这种状态。(获取不到缩就会被转换成 SIGNAL)
  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)
            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; // head的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); // 唤醒
    }

    总结  : 我被 unpark但是 又被别人抢了, 那我 就 会 自旋,在挂起 , 所以无论怎么讲这是 多个线程表演的舞台,他们各尽其能去获取, 是通过CAS 控制的 保证的。  有队列,有插队。

啊四大四大四大

posted @ 2017-07-26 18:00  默默无语敲代码  阅读(162)  评论(0编辑  收藏  举报