zoukankan      html  css  js  c++  java
  • AbstractQueuedSynchronizer

    在不同模式等待的线程共用一个FIFO队列,子类实现独占模式或者共享模式不需要定义支持另一个模式的方法。

    使用方法:通过使用getState,setState,和compareAndSetState方法来重写以下方法

    ①tryAcquire

    ②tryRelease

    ③tryAcquireShared

    ④tryReleaseShared

    ⑤isHeldExclusively

    定义这些方法是使用这个类的唯一手段,因为其他方法都被定义为final。

    实现公平锁:

    如果方法hasQueuedPredecessors(特别为公平锁设计的方法)返回true,则方法tryAcquire返回false

    示例用法:

     1 class Mutex implements Lock, java.io.Serializable {
     2  
     3             // Our internal helper class
     4             private static class Sync extends AbstractQueuedSynchronizer {
     5       // Reports whether in locked state
     6               protected boolean isHeldExclusively() {
     7         return getState() == 1;
     8       }
     9  
    10               // Acquires the lock if state is zero
    11               public boolean tryAcquire(int acquires) {
    12         assert acquires == 1; // Otherwise unused
    13         if (compareAndSetState(0, 1)) {
    14           setExclusiveOwnerThread(Thread.currentThread());
    15           return true;
    16         }
    17         return false;
    18       }
    19  
    20               // Releases the lock by setting state to zero
    21               protected boolean tryRelease(int releases) {
    22         assert releases == 1; // Otherwise unused
    23         if (getState() == 0) throw new IllegalMonitorStateException();
    24         setExclusiveOwnerThread(null);
    25         setState(0);
    26         return true;
    27       }
    28  
    29               // Provides a Condition
    30               Condition newCondition() { return new ConditionObject(); }
    31  
    32               // Deserializes properly
    33               private void readObject(ObjectInputStream s)
    34           throws IOException, ClassNotFoundException {
    35         s.defaultReadObject();
    36         setState(0); // reset to unlocked state
    37       }
    38     }
    39  
    40             // The sync object does all the hard work. We just forward to it.
    41             private final Sync sync = new Sync();
    42  
    43             public void lock()                { sync.acquire(1); }
    44     public boolean tryLock()          { return sync.tryAcquire(1); }
    45     public void unlock()              { sync.release(1); }
    46     public Condition newCondition()   { return sync.newCondition(); }
    47     public boolean isLocked()         { return sync.isHeldExclusively(); }
    48     public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
    49     public void lockInterruptibly() throws InterruptedException {
    50       sync.acquireInterruptibly(1);
    51     }
    52     public boolean tryLock(long timeout, TimeUnit unit)
    53         throws InterruptedException {
    54       return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    55     }
    56   }

    内部方法解释:

    /**
    * Wakes up node's successor, if one exists.
    *
    * @param node the node
    */
    private void unparkSuccessor(Node node)

    将当前节点的waitStatus < 0,则设置为0,唤醒下一个waitStatus<=0的线程

    lock加锁操作:

    调用acquire(1),该方法在AQS里:

     1 /**
     2      * Acquires in exclusive mode, ignoring interrupts.  Implemented
     3      * by invoking at least once {@link #tryAcquire},
     4      * returning on success.  Otherwise the thread is queued, possibly
     5      * repeatedly blocking and unblocking, invoking {@link
     6      * #tryAcquire} until success.  This method can be used
     7      * to implement method {@link Lock#lock}.
     8      *
     9      * @param arg the acquire argument.  This value is conveyed to
    10      *        {@link #tryAcquire} but is otherwise uninterpreted and
    11      *        can represent anything you like.
    12      */
    13     public final void acquire(int arg) {
    14         if (!tryAcquire(arg) &&
    15             acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
    16             selfInterrupt();
    17     }

    该方法先尝试获取锁,获取锁的动作就是使用CAS操作来设置state字段的值,如果成功则exclusiveOwnerThread字段设置为当前的线程对象。

    如果尝试失败,则先构建一个EXCLUSIVE节点插入链表,然后执行acquireQueued方法:

     1 /**
     2      * Acquires in exclusive uninterruptible mode for thread already in
     3      * queue. Used by condition wait methods as well as acquire.
     4      *
     5      * @param node the node
     6      * @param arg the acquire argument
     7      * @return {@code true} if interrupted while waiting
     8      */
     9     final boolean acquireQueued(final Node node, int arg) {
    10         boolean failed = true;
    11         try {
    12             boolean interrupted = false;
    13             for (;;) {
    14                 final Node p = node.predecessor();
    15                 if (p == head && tryAcquire(arg)) {
    16                     setHead(node);
    17                     p.next = null; // help GC
    18                     failed = false;
    19                     return interrupted;
    20                 }
    21                 if (shouldParkAfterFailedAcquire(p, node) &&
    22                     parkAndCheckInterrupt())
    23                     interrupted = true;
    24             }
    25         } finally {
    26             if (failed)
    27                 cancelAcquire(node);
    28         }
    29     }

    该方法将当前线程park(阻塞),然后返回在阻塞前,当前线程的interrupted状态是否为true。(注:如果当前线程的interrupted==true的话,调用park不会阻塞线程,而是立即返回。而wait方法是抛出异常

    unlock解锁操作:

    调用release方法:

     1 /**
     2      * Releases in exclusive mode.  Implemented by unblocking one or
     3      * more threads if {@link #tryRelease} returns true.
     4      * This method can be used to implement method {@link Lock#unlock}.
     5      *
     6      * @param arg the release argument.  This value is conveyed to
     7      *        {@link #tryRelease} but is otherwise uninterpreted and
     8      *        can represent anything you like.
     9      * @return the value returned from {@link #tryRelease}
    10      */
    11     public final boolean release(int arg) {
    12         if (tryRelease(arg)) {
    13             Node h = head;
    14             if (h != null && h.waitStatus != 0)
    15                 unparkSuccessor(h);
    16             return true;
    17         }
    18         return false;
    19     }

    从链表中找到一个节点线程唤醒。

    这里只是说了个大概,并发编程时有许多细节需要考虑才能既做到并发安全又做到比较好的性能。

  • 相关阅读:
    MYSQL 使用DBI
    mysql 更改数据目录
    Error Code: 1360
    org.hibernate.exception.GenericJDBCException: Could not open connection
    Error: Dynamic is undefined
    Unhandled event loop exception No more handles
    Count:858org.apache.jasper.JasperException: Unable to compile class for JSP
    Mysql --skip-grant-table
    第24章-启动 停止 和配置mysql
    Linux 6.2 x86_64 安装ipvs
  • 原文地址:https://www.cnblogs.com/CLAYJJ/p/9599776.html
Copyright © 2011-2022 走看看