码迷,mamicode.com
首页 > 其他好文 > 详细

JUC半日游

时间:2019-07-28 10:59:29      阅读:111      评论:0      收藏:0      [点我收藏+]

标签:设立   read   orm   node   wak   anti   lse   mini   双向   

AQS

  • 关于CLH大量使用到的Unsafe的CAS用法,头两个入参是this和xxOffset,翻了一下牛逼网友的给的代码大概是处理一个内存对齐的问题,整个操作中涉及到offset(dest)有两个部分

    mov edx, dest
    .....
    cmpxchg dword ptr [edx], ecx   ;ecx寄存器放置exchange_value
  • Unsafe不面向普通开发者,上来就检查你的类加载器是不是null(native)

  • 先mark一下这句话,其中AbstractOwnableSynchronizer就是保存有排斥用的Thread成员

    * You may also find the inherited methods from {@link
    * AbstractOwnableSynchronizer} useful to keep track of the thread
    * owning an exclusive synchronizer.  You are encouraged to use them
    * -- this enables monitoring and diagnostic tools to assist users in
    * determining which threads hold locks.
  • A thread may try to acquire if it is first in the queue.(这是一个FIFO机制)

  • CLH锁的入队是原子性的(源码中使用CAS(新的节点,tail)实现替换) Insertion into a CLH queue requires only a single atomic operation on "tail",且出队也是原子性的,dequeuing involves only updating the "head",但还需要处理后继 in part to deal with possible cancellation due to timeouts and interrupts,所有的信息都用volatile的waitStatus来表示,比方说取消(timeout or interrupt)是1,SIGNAL(当前的后继需要唤醒,注意有特殊的要求, unpark its successor when it releases or cancels)为-1,而-2 / -3 涉及到Condition的设计,这里暂且保留说明

  • 链表设计中prev用于处理取消操作,next用于处理阻塞操作,当需要wakeup时就沿着next来跑(其中有一点checking backwards from the atomically updated "tail" when a node‘s successor appears to be null的情形暂留)

  • nextWaiternext有一定区别,前者是一个简单的node,而后者是volatile,具体用途似乎不止一种,有一种用法是判断是否共享/独占nextWaiter == SHARED

  • statestatus又有啥区别啊(The synchronization state.好含糊啊,推测是可重入设计中的资源状态)

  • CLH队列有独占(null)和共享(一个空的Node())两种模式,分别为ReentranceLock和Semaphore/CyclicBarrier等线程通信工具提供实现基类

  • CLH locks are normally used forspinlocks

  • A node is signalled when its predecessor releases.

  • enqueue操作是通过CAS来实现双向链表的,详见line583:enq(好奇队列为空时设立head的操作,大概是一种lazy设计)

  • 为什么unpark需要从后往前遍历,需要看并发情况下的原子性,当CAStail为新的node时,原tail的next并不指向真正的tail,而prev保证了必然能遍历到所有的node(再次给大佬跪了,懵逼了好久orz)

    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)) {
                        // 刚好发生意外 新的tail.prev肯定有了,但旧的tail.next还是null
                        t.next = node;
                        return t;
                    }
                }
            }
        }
    
    
    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;
        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);
    }

JUC半日游

标签:设立   read   orm   node   wak   anti   lse   mini   双向   

原文地址:https://www.cnblogs.com/caturra/p/11258131.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!