zoukankan      html  css  js  c++  java
  • 分析NonfairSync加锁/解锁过程

    类继承关系:

    NonfairSync => Sync => AbstractQueuedSynchronizer

    类NonfairSync

    final void lock() {

        if (compareAndSetState(0, 1))

            setExclusiveOwnerThread(Thread.currentThread());

        else

            acquire(1);

    }

    分析:

    compareAndSetState(0, 1):通过cas操作更新state状态,若成功,则获取到锁,否则,进行排队申请操作acquire

    类AbstractQueuedSynchronizer

    public final void acquire(int arg) {

        if (!tryAcquire(arg) &&

            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

            selfInterrupt();

    }

    分析:

    tryAcquire方法最终实现为:

    类Sync

    final boolean nonfairTryAcquire(int acquires) {

        final Thread current = Thread.currentThread();

        int c = getState();

        if (c == 0) {

            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");

            setState(nextc);

            return true;

        }

        return false;

    }

    通过cas操作更新state状态,若成功,则获取到锁,否则,首先进行排队,

    类AbstractQueuedSynchronizer

    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(node);

        return node;

    }

    注意:

    每一个线程被封装成一个Node节点。

    进入enq方法——入队列

    private Node enq(final Node node) {

        for (;;) {

            Node t = tail;

            if (t == null) { // Must initialize

                if (compareAndSetHead(new Node()))

                    tail = head;

            } else {

                node.prev = t;

                if (compareAndSetTail(t, node)) {

                    t.next = node;

                    return t;

                }

            }

        }

    }

    分析:

    这里针对head和tail属性的赋值均为cas原子操作。

    最终模型如图:

     

    如果多线程并发入队,最终结果如图:

     

    注:prev和next分别为Node类的两个属性

    入队操作结束后,开始请求队列acquireQueued

    类AbstractQueuedSynchronizer

    final boolean acquireQueued(final Node node, int arg) {

        boolean failed = true;

        try {

            boolean interrupted = false;

            for (;;) {

                final Node p = node.predecessor();

                if (p == head && tryAcquire(arg)) {

                    setHead(node);

                    p.next = null; // help GC

                    failed = false;

                    return interrupted;

                }

                if (shouldParkAfterFailedAcquire(p, node) &&

                    parkAndCheckInterrupt())

                    interrupted = true;

            }

        } finally {

            if (failed)

                cancelAcquire(node);

        }

    }

    分析:

    1. Node p = node.predecessor()获取node的prev节点
    2. 如果prev==head节点并且tryAcquire返回true,则更新head节点为当前节点,并退出循环,也就获取到了锁。
    3. 否则的话,执行shouldParkAfterFailedAcquire和parkAndCheckInterrupt。
    4. setHead方法来修改head属性,改变队列的头部节点

      其中,shouldParkAfterFailedAcquire方法是针对waitStatus属性的修改

      private final boolean parkAndCheckInterrupt() {

          LockSupport.park(this);

          return Thread.interrupted();

      }

      LockSupport.park(this),使当前线程进入阻塞。

    unlock分析

    类AbstractQueuedSynchronizer

    public final boolean release(int arg) {

        if (tryRelease(arg)) {

            Node h = head;

            if (h != null && h.waitStatus != 0)

                unparkSuccessor(h);

            return true;

        }

        return false;

    }

    类Sync

    protected final boolean tryRelease(int releases) {

        int c = getState() - releases;

        if (Thread.currentThread() != getExclusiveOwnerThread())

            throw new IllegalMonitorStateException();

        boolean free = false;

        if (c == 0) {

            free = true;

            setExclusiveOwnerThread(null);

        }

        setState(c);

        return free;

    }

    分析:

    主要工作就是设置还原state状态

    类AbstractQueuedSynchronizer

    private void unparkSuccessor(Node node) {

        int ws = node.waitStatus;

        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;

        }

        if (s != null)

            LockSupport.unpark(s.thread);

    }

    分析:

    1. 入参node即head节点
    2. Node s = node.next;即获取到下一个节点,即正在阻塞中的线程
    3. LockSupport.unpark(s.thread);即激活线程
  • 相关阅读:
    kerberos和hadoop的集成
    kerberos的原理
    Impala与Hive的异同
    为什么hdfs不适合存储小文件
    猛犸数据质量
    CIO的发展之路
    企业数据能力测评:认清现状,布局未来
    企业架构的演变
    其实,他只是个没长大的孩子【复制知乎
    看着自己之前写的便签,想笑
  • 原文地址:https://www.cnblogs.com/liuxinan/p/5633879.html
Copyright © 2011-2022 走看看