Java多线程系列--“JUC锁”07之 LockSupport (r)

来源:互联网 发布:海战网络手游哪个好玩 编辑:程序博客网 时间:2024/06/05 09:06

概述

本章介绍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 lock101  *     while (waiters.peek() != current ||102  *            !locked.compareAndSet(false, true)) {103  *        LockSupport.park(this);104  *        if (Thread.interrupted()) // ignore interrupts while waiting105  *          wasInterrupted = true;106  *     }107  *108  *     waiters.remove();109  *     if (wasInterrupted)          // reassert interrupt status on exit110  *        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 API124     private static final Unsafe unsafe = Unsafe.getUnsafe();125     private static final long parkBlockerOffset;126 127     static {128         try {129             parkBlockerOffset = unsafe.objectFieldOffset130                 (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 it141      * was not already available.  If the thread was blocked on142      * {@code park} then it will unblock.  Otherwise, its next call143      * to {@code park} is guaranteed not to block. This operation144      * is not guaranteed to have any effect at all if the given145      * thread has not been started.146      *147      * @param thread the thread to unpark, or {@code null}, in which case148      *        this operation has no effect149      */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 the157      * permit is available.158      *159      * <p>If the permit is available then it is consumed and the call returns160      * immediately; otherwise161      * the current thread becomes disabled for thread scheduling162      * purposes and lies dormant until one of three things happens:163      *164      * <ul>165      * <li>Some other thread invokes {@link #unpark unpark} with the166      * current thread as the target; or167      *168      * <li>Some other thread {@linkplain Thread#interrupt interrupts}169      * the current thread; or170      *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 the175      * method to return. Callers should re-check the conditions which caused176      * 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 this180      *        thread parking181      * @since 1.6182      */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 to192      * the specified waiting time, unless the permit is available.193      *194      * <p>If the permit is available then it is consumed and the call195      * returns immediately; otherwise the current thread becomes disabled196      * for thread scheduling purposes and lies dormant until one of four197      * things happens:198      *199      * <ul>200      * <li>Some other thread invokes {@link #unpark unpark} with the201      * current thread as the target; or202      *203      * <li>Some other thread {@linkplain Thread#interrupt interrupts}204      * the current thread; or205      *206      * <li>The specified waiting time elapses; or207      *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 the212      * method to return. Callers should re-check the conditions which caused213      * the thread to park in the first place. Callers may also determine,214      * for example, the interrupt status of the thread, or the elapsed time215      * upon return.216      *217      * @param blocker the synchronization object responsible for this218      *        thread parking219      * @param nanos the maximum number of nanoseconds to wait220      * @since 1.6221      */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, until233      * the specified deadline, unless the permit is available.234      *235      * <p>If the permit is available then it is consumed and the call236      * returns immediately; otherwise the current thread becomes disabled237      * for thread scheduling purposes and lies dormant until one of four238      * things happens:239      *240      * <ul>241      * <li>Some other thread invokes {@link #unpark unpark} with the242      * current thread as the target; or243      *244      * <li>Some other thread {@linkplain Thread#interrupt interrupts} the245      * current thread; or246      *247      * <li>The specified deadline passes; or248      *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 the253      * method to return. Callers should re-check the conditions which caused254      * the thread to park in the first place. Callers may also determine,255      * for example, the interrupt status of the thread, or the current time256      * upon return.257      *258      * @param blocker the synchronization object responsible for this259      *        thread parking260      * @param deadline the absolute time, in milliseconds from the Epoch,261      *        to wait until262      * @since 1.6263      */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 recent273      * invocation of a park method that has not yet unblocked, or null274      * if not blocked.  The value returned is just a momentary275      * snapshot -- the thread may have since unblocked or blocked on a276      * different blocker object.277      *278      * @param t the thread279      * @return the blocker280      * @throws NullPointerException if argument is null281      * @since 1.6282      */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 the291      * permit is available.292      *293      * <p>If the permit is available then it is consumed and the call294      * returns immediately; otherwise the current thread becomes disabled295      * for thread scheduling purposes and lies dormant until one of three296      * things happens:297      *298      * <ul>299      *300      * <li>Some other thread invokes {@link #unpark unpark} with the301      * current thread as the target; or302      *303      * <li>Some other thread {@linkplain Thread#interrupt interrupts}304      * the current thread; or305      *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 the310      * method to return. Callers should re-check the conditions which caused311      * 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 to320      * the specified waiting time, unless the permit is available.321      *322      * <p>If the permit is available then it is consumed and the call323      * returns immediately; otherwise the current thread becomes disabled324      * for thread scheduling purposes and lies dormant until one of four325      * things happens:326      *327      * <ul>328      * <li>Some other thread invokes {@link #unpark unpark} with the329      * current thread as the target; or330      *331      * <li>Some other thread {@linkplain Thread#interrupt interrupts}332      * the current thread; or333      *334      * <li>The specified waiting time elapses; or335      *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 the340      * method to return. Callers should re-check the conditions which caused341      * the thread to park in the first place. Callers may also determine,342      * for example, the interrupt status of the thread, or the elapsed time343      * upon return.344      *345      * @param nanos the maximum number of nanoseconds to wait346      */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, until354      * the specified deadline, unless the permit is available.355      *356      * <p>If the permit is available then it is consumed and the call357      * returns immediately; otherwise the current thread becomes disabled358      * for thread scheduling purposes and lies dormant until one of four359      * things happens:360      *361      * <ul>362      * <li>Some other thread invokes {@link #unpark unpark} with the363      * current thread as the target; or364      *365      * <li>Some other thread {@linkplain Thread#interrupt interrupts}366      * the current thread; or367      *368      * <li>The specified deadline passes; or369      *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 the374      * method to return. Callers should re-check the conditions which caused375      * the thread to park in the first place. Callers may also determine,376      * for example, the interrupt status of the thread, or the current time377      * upon return.378      *379      * @param deadline the absolute time, in milliseconds from the Epoch,380      *        to wait until381      */382     public static void parkUntil(long deadline) {383         unsafe.park(true, deadline);384     }385 }
复制代码

说明: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 tamain blockta wakup othersmain 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篇) 

 

0 0