• Java多线程系列--“JUC锁”07之 LockSupport


     

    概述

    本章介绍JUC(java.util.concurrent)包中的LockSupport。内容包括:
    LockSupport介绍
    LockSupport函数列表
    LockSupport参考代码(基于JDK1.7.0_40)
    LockSupport示例

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3505784.html

    LockSupport介绍

    LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
    LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()和unpark()不会遇到“Thread.suspend 和 Thread.resume所可能引发的死锁”问题。
    因为park() 和 unpark()有许可的存在;调用 park() 的线程和另一个试图将其 unpark() 的线程之间的竞争将保持活性。

    LockSupport函数列表

    // 返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null。
    static Object getBlocker(Thread t)
    // 为了线程调度,禁用当前线程,除非许可可用。
    static void park()
    // 为了线程调度,在许可可用之前禁用当前线程。
    static void park(Object blocker)
    // 为了线程调度禁用当前线程,最多等待指定的等待时间,除非许可可用。
    static void parkNanos(long nanos)
    // 为了线程调度,在许可可用前禁用当前线程,并最多等待指定的等待时间。
    static void parkNanos(Object blocker, long nanos)
    // 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
    static void parkUntil(long deadline)
    // 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
    static void parkUntil(Object blocker, long deadline)
    // 如果给定线程的许可尚不可用,则使其可用。
    static void unpark(Thread thread)

    LockSupport参考代码(基于JDK1.7.0_40)

    LockSupport.java的源码如下:

      1 /*
      2  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
      3  *
      4  *
      5  *
      6  *
      7  *
      8  *
      9  *
     10  *
     11  *
     12  *
     13  *
     14  *
     15  *
     16  *
     17  *
     18  *
     19  *
     20  *
     21  *
     22  *
     23  */
     24 
     25 /*
     26  *
     27  *
     28  *
     29  *
     30  *
     31  * Written by Doug Lea with assistance from members of JCP JSR-166
     32  * Expert Group and released to the public domain, as explained at
     33  * http://creativecommons.org/publicdomain/zero/1.0/
     34  */
     35 
     36 package java.util.concurrent.locks;
     37 import java.util.concurrent.*;
     38 import sun.misc.Unsafe;
     39 
     40 
     41 /**
     42  * Basic thread blocking primitives for creating locks and other
     43  * synchronization classes.
     44  *
     45  * <p>This class associates, with each thread that uses it, a permit
     46  * (in the sense of the {@link java.util.concurrent.Semaphore
     47  * Semaphore} class). A call to {@code park} will return immediately
     48  * if the permit is available, consuming it in the process; otherwise
     49  * it <em>may</em> block.  A call to {@code unpark} makes the permit
     50  * available, if it was not already available. (Unlike with Semaphores
     51  * though, permits do not accumulate. There is at most one.)
     52  *
     53  * <p>Methods {@code park} and {@code unpark} provide efficient
     54  * means of blocking and unblocking threads that do not encounter the
     55  * problems that cause the deprecated methods {@code Thread.suspend}
     56  * and {@code Thread.resume} to be unusable for such purposes: Races
     57  * between one thread invoking {@code park} and another thread trying
     58  * to {@code unpark} it will preserve liveness, due to the
     59  * permit. Additionally, {@code park} will return if the caller's
     60  * thread was interrupted, and timeout versions are supported. The
     61  * {@code park} method may also return at any other time, for "no
     62  * reason", so in general must be invoked within a loop that rechecks
     63  * conditions upon return. In this sense {@code park} serves as an
     64  * optimization of a "busy wait" that does not waste as much time
     65  * spinning, but must be paired with an {@code unpark} to be
     66  * effective.
     67  *
     68  * <p>The three forms of {@code park} each also support a
     69  * {@code blocker} object parameter. This object is recorded while
     70  * the thread is blocked to permit monitoring and diagnostic tools to
     71  * identify the reasons that threads are blocked. (Such tools may
     72  * access blockers using method {@link #getBlocker}.) The use of these
     73  * forms rather than the original forms without this parameter is
     74  * strongly encouraged. The normal argument to supply as a
     75  * {@code blocker} within a lock implementation is {@code this}.
     76  *
     77  * <p>These methods are designed to be used as tools for creating
     78  * higher-level synchronization utilities, and are not in themselves
     79  * useful for most concurrency control applications.  The {@code park}
     80  * method is designed for use only in constructions of the form:
     81  * <pre>while (!canProceed()) { ... LockSupport.park(this); }</pre>
     82  * where neither {@code canProceed} nor any other actions prior to the
     83  * call to {@code park} entail locking or blocking.  Because only one
     84  * permit is associated with each thread, any intermediary uses of
     85  * {@code park} could interfere with its intended effects.
     86  *
     87  * <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out
     88  * non-reentrant lock class:
     89  * <pre>{@code
     90  * class FIFOMutex {
     91  *   private final AtomicBoolean locked = new AtomicBoolean(false);
     92  *   private final Queue<Thread> waiters
     93  *     = new ConcurrentLinkedQueue<Thread>();
     94  *
     95  *   public void lock() {
     96  *     boolean wasInterrupted = false;
     97  *     Thread current = Thread.currentThread();
     98  *     waiters.add(current);
     99  *
    100  *     // Block while not first in queue or cannot acquire lock
    101  *     while (waiters.peek() != current ||
    102  *            !locked.compareAndSet(false, true)) {
    103  *        LockSupport.park(this);
    104  *        if (Thread.interrupted()) // ignore interrupts while waiting
    105  *          wasInterrupted = true;
    106  *     }
    107  *
    108  *     waiters.remove();
    109  *     if (wasInterrupted)          // reassert interrupt status on exit
    110  *        current.interrupt();
    111  *   }
    112  *
    113  *   public void unlock() {
    114  *     locked.set(false);
    115  *     LockSupport.unpark(waiters.peek());
    116  *   }
    117  * }}</pre>
    118  */
    119 
    120 public class LockSupport {
    121     private LockSupport() {} // Cannot be instantiated.
    122 
    123     // Hotspot implementation via intrinsics API
    124     private static final Unsafe unsafe = Unsafe.getUnsafe();
    125     private static final long parkBlockerOffset;
    126 
    127     static {
    128         try {
    129             parkBlockerOffset = unsafe.objectFieldOffset
    130                 (java.lang.Thread.class.getDeclaredField("parkBlocker"));
    131         } catch (Exception ex) { throw new Error(ex); }
    132     }
    133 
    134     private static void setBlocker(Thread t, Object arg) {
    135         // Even though volatile, hotspot doesn't need a write barrier here.
    136         unsafe.putObject(t, parkBlockerOffset, arg);
    137     }
    138 
    139     /**
    140      * Makes available the permit for the given thread, if it
    141      * was not already available.  If the thread was blocked on
    142      * {@code park} then it will unblock.  Otherwise, its next call
    143      * to {@code park} is guaranteed not to block. This operation
    144      * is not guaranteed to have any effect at all if the given
    145      * thread has not been started.
    146      *
    147      * @param thread the thread to unpark, or {@code null}, in which case
    148      *        this operation has no effect
    149      */
    150     public static void unpark(Thread thread) {
    151         if (thread != null)
    152             unsafe.unpark(thread);
    153     }
    154 
    155     /**
    156      * Disables the current thread for thread scheduling purposes unless the
    157      * permit is available.
    158      *
    159      * <p>If the permit is available then it is consumed and the call returns
    160      * immediately; otherwise
    161      * the current thread becomes disabled for thread scheduling
    162      * purposes and lies dormant until one of three things happens:
    163      *
    164      * <ul>
    165      * <li>Some other thread invokes {@link #unpark unpark} with the
    166      * current thread as the target; or
    167      *
    168      * <li>Some other thread {@linkplain Thread#interrupt interrupts}
    169      * the current thread; or
    170      *
    171      * <li>The call spuriously (that is, for no reason) returns.
    172      * </ul>
    173      *
    174      * <p>This method does <em>not</em> report which of these caused the
    175      * method to return. Callers should re-check the conditions which caused
    176      * the thread to park in the first place. Callers may also determine,
    177      * for example, the interrupt status of the thread upon return.
    178      *
    179      * @param blocker the synchronization object responsible for this
    180      *        thread parking
    181      * @since 1.6
    182      */
    183     public static void park(Object blocker) {
    184         Thread t = Thread.currentThread();
    185         setBlocker(t, blocker);
    186         unsafe.park(false, 0L);
    187         setBlocker(t, null);
    188     }
    189 
    190     /**
    191      * Disables the current thread for thread scheduling purposes, for up to
    192      * the specified waiting time, unless the permit is available.
    193      *
    194      * <p>If the permit is available then it is consumed and the call
    195      * returns immediately; otherwise the current thread becomes disabled
    196      * for thread scheduling purposes and lies dormant until one of four
    197      * things happens:
    198      *
    199      * <ul>
    200      * <li>Some other thread invokes {@link #unpark unpark} with the
    201      * current thread as the target; or
    202      *
    203      * <li>Some other thread {@linkplain Thread#interrupt interrupts}
    204      * the current thread; or
    205      *
    206      * <li>The specified waiting time elapses; or
    207      *
    208      * <li>The call spuriously (that is, for no reason) returns.
    209      * </ul>
    210      *
    211      * <p>This method does <em>not</em> report which of these caused the
    212      * method to return. Callers should re-check the conditions which caused
    213      * the thread to park in the first place. Callers may also determine,
    214      * for example, the interrupt status of the thread, or the elapsed time
    215      * upon return.
    216      *
    217      * @param blocker the synchronization object responsible for this
    218      *        thread parking
    219      * @param nanos the maximum number of nanoseconds to wait
    220      * @since 1.6
    221      */
    222     public static void parkNanos(Object blocker, long nanos) {
    223         if (nanos > 0) {
    224             Thread t = Thread.currentThread();
    225             setBlocker(t, blocker);
    226             unsafe.park(false, nanos);
    227             setBlocker(t, null);
    228         }
    229     }
    230 
    231     /**
    232      * Disables the current thread for thread scheduling purposes, until
    233      * the specified deadline, unless the permit is available.
    234      *
    235      * <p>If the permit is available then it is consumed and the call
    236      * returns immediately; otherwise the current thread becomes disabled
    237      * for thread scheduling purposes and lies dormant until one of four
    238      * things happens:
    239      *
    240      * <ul>
    241      * <li>Some other thread invokes {@link #unpark unpark} with the
    242      * current thread as the target; or
    243      *
    244      * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
    245      * current thread; or
    246      *
    247      * <li>The specified deadline passes; or
    248      *
    249      * <li>The call spuriously (that is, for no reason) returns.
    250      * </ul>
    251      *
    252      * <p>This method does <em>not</em> report which of these caused the
    253      * method to return. Callers should re-check the conditions which caused
    254      * the thread to park in the first place. Callers may also determine,
    255      * for example, the interrupt status of the thread, or the current time
    256      * upon return.
    257      *
    258      * @param blocker the synchronization object responsible for this
    259      *        thread parking
    260      * @param deadline the absolute time, in milliseconds from the Epoch,
    261      *        to wait until
    262      * @since 1.6
    263      */
    264     public static void parkUntil(Object blocker, long deadline) {
    265         Thread t = Thread.currentThread();
    266         setBlocker(t, blocker);
    267         unsafe.park(true, deadline);
    268         setBlocker(t, null);
    269     }
    270 
    271     /**
    272      * Returns the blocker object supplied to the most recent
    273      * invocation of a park method that has not yet unblocked, or null
    274      * if not blocked.  The value returned is just a momentary
    275      * snapshot -- the thread may have since unblocked or blocked on a
    276      * different blocker object.
    277      *
    278      * @param t the thread
    279      * @return the blocker
    280      * @throws NullPointerException if argument is null
    281      * @since 1.6
    282      */
    283     public static Object getBlocker(Thread t) {
    284         if (t == null)
    285             throw new NullPointerException();
    286         return unsafe.getObjectVolatile(t, parkBlockerOffset);
    287     }
    288 
    289     /**
    290      * Disables the current thread for thread scheduling purposes unless the
    291      * permit is available.
    292      *
    293      * <p>If the permit is available then it is consumed and the call
    294      * returns immediately; otherwise the current thread becomes disabled
    295      * for thread scheduling purposes and lies dormant until one of three
    296      * things happens:
    297      *
    298      * <ul>
    299      *
    300      * <li>Some other thread invokes {@link #unpark unpark} with the
    301      * current thread as the target; or
    302      *
    303      * <li>Some other thread {@linkplain Thread#interrupt interrupts}
    304      * the current thread; or
    305      *
    306      * <li>The call spuriously (that is, for no reason) returns.
    307      * </ul>
    308      *
    309      * <p>This method does <em>not</em> report which of these caused the
    310      * method to return. Callers should re-check the conditions which caused
    311      * the thread to park in the first place. Callers may also determine,
    312      * for example, the interrupt status of the thread upon return.
    313      */
    314     public static void park() {
    315         unsafe.park(false, 0L);
    316     }
    317 
    318     /**
    319      * Disables the current thread for thread scheduling purposes, for up to
    320      * the specified waiting time, unless the permit is available.
    321      *
    322      * <p>If the permit is available then it is consumed and the call
    323      * returns immediately; otherwise the current thread becomes disabled
    324      * for thread scheduling purposes and lies dormant until one of four
    325      * things happens:
    326      *
    327      * <ul>
    328      * <li>Some other thread invokes {@link #unpark unpark} with the
    329      * current thread as the target; or
    330      *
    331      * <li>Some other thread {@linkplain Thread#interrupt interrupts}
    332      * the current thread; or
    333      *
    334      * <li>The specified waiting time elapses; or
    335      *
    336      * <li>The call spuriously (that is, for no reason) returns.
    337      * </ul>
    338      *
    339      * <p>This method does <em>not</em> report which of these caused the
    340      * method to return. Callers should re-check the conditions which caused
    341      * the thread to park in the first place. Callers may also determine,
    342      * for example, the interrupt status of the thread, or the elapsed time
    343      * upon return.
    344      *
    345      * @param nanos the maximum number of nanoseconds to wait
    346      */
    347     public static void parkNanos(long nanos) {
    348         if (nanos > 0)
    349             unsafe.park(false, nanos);
    350     }
    351 
    352     /**
    353      * Disables the current thread for thread scheduling purposes, until
    354      * the specified deadline, unless the permit is available.
    355      *
    356      * <p>If the permit is available then it is consumed and the call
    357      * returns immediately; otherwise the current thread becomes disabled
    358      * for thread scheduling purposes and lies dormant until one of four
    359      * things happens:
    360      *
    361      * <ul>
    362      * <li>Some other thread invokes {@link #unpark unpark} with the
    363      * current thread as the target; or
    364      *
    365      * <li>Some other thread {@linkplain Thread#interrupt interrupts}
    366      * the current thread; or
    367      *
    368      * <li>The specified deadline passes; or
    369      *
    370      * <li>The call spuriously (that is, for no reason) returns.
    371      * </ul>
    372      *
    373      * <p>This method does <em>not</em> report which of these caused the
    374      * method to return. Callers should re-check the conditions which caused
    375      * the thread to park in the first place. Callers may also determine,
    376      * for example, the interrupt status of the thread, or the current time
    377      * upon return.
    378      *
    379      * @param deadline the absolute time, in milliseconds from the Epoch,
    380      *        to wait until
    381      */
    382     public static void parkUntil(long deadline) {
    383         unsafe.park(true, deadline);
    384     }
    385 }
    View Code

    说明:LockSupport是通过调用Unsafe函数中的接口实现阻塞和解除阻塞的。

    LockSupport示例

    对比下面的“示例1”和“示例2”可以更清晰的了解LockSupport的用法。

    示例1

     1 public class WaitTest1 {
     2 
     3     public static void main(String[] args) {
     4 
     5         ThreadA ta = new ThreadA("ta");
     6 
     7         synchronized(ta) { // 通过synchronized(ta)获取“对象ta的同步锁”
     8             try {
     9                 System.out.println(Thread.currentThread().getName()+" start ta");
    10                 ta.start();
    11 
    12                 System.out.println(Thread.currentThread().getName()+" block");
    13                 // 主线程等待
    14                 ta.wait();
    15 
    16                 System.out.println(Thread.currentThread().getName()+" continue");
    17             } catch (InterruptedException e) {
    18                 e.printStackTrace();
    19             }
    20         }
    21     }
    22 
    23     static class ThreadA extends Thread{
    24 
    25         public ThreadA(String name) {
    26             super(name);
    27         }
    28 
    29         public void run() {
    30             synchronized (this) { // 通过synchronized(this)获取“当前对象的同步锁”
    31                 System.out.println(Thread.currentThread().getName()+" wakup others");
    32                 notify();    // 唤醒“当前对象上的等待线程”
    33             }
    34         }
    35     }
    36 }

    示例2

     1 import java.util.concurrent.locks.LockSupport;
     2 
     3 public class LockSupportTest1 {
     4 
     5     private static Thread mainThread;
     6 
     7     public static void main(String[] args) {
     8 
     9         ThreadA ta = new ThreadA("ta");
    10         // 获取主线程
    11         mainThread = Thread.currentThread();
    12 
    13         System.out.println(Thread.currentThread().getName()+" start ta");
    14         ta.start();
    15 
    16         System.out.println(Thread.currentThread().getName()+" block");
    17         // 主线程阻塞
    18         LockSupport.park(mainThread);
    19 
    20         System.out.println(Thread.currentThread().getName()+" continue");
    21     }
    22 
    23     static class ThreadA extends Thread{
    24 
    25         public ThreadA(String name) {
    26             super(name);
    27         }
    28 
    29         public void run() {
    30             System.out.println(Thread.currentThread().getName()+" wakup others");
    31             // 唤醒“主线程”
    32             LockSupport.unpark(mainThread);
    33         }
    34     }
    35 }

    运行结果

    main start ta
    main block
    ta wakup others
    main continue

    说明:park和wait的区别。wait让线程阻塞前,必须通过synchronized获取同步锁。


    更多内容 

    1. Java多线程系列--“JUC锁”01之 框架 

    2. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock 

    3. Java多线程系列--“JUC锁”03之 公平锁(一) 

    4. Java多线程系列--“JUC锁”04之 公平锁(二) 

    5. Java多线程系列--“JUC锁”05之 非公平锁

    6. Java多线程系列--“JUC锁”06之 Condition条件

    7. Java多线程系列目录(共xx篇) 

  • 相关阅读:
    Hadoop之MapReduce学习(一)
    Spark 0.9.0启动脚本——bin/run-example
    Spark 0.9.0启动脚本——sbin/spark-daemon.sh
    Spark 0.9.0启动脚本——启动总结
    Spark 0.9.0启动脚本——sbin/start-slave.sh
    Spark 0.9.0启动脚本——sbin/slaves.sh
    Spark 0.9.0启动脚本——sbin/start-slaves.sh
    Spark 0.9.0启动脚本——sbin/start-master.sh
    Spark 0.9.0启动脚本——sbin/spark-config.sh
    Hadoop 2.2.0启动脚本——bin/hdfs
  • 原文地址:https://www.cnblogs.com/skywang12345/p/3505784.html
Copyright © 2020-2023  润新知