skywang12345

导航

统计
 

 

概述

本章介绍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篇) 

 

posted on 2014-01-25 10:41 如果天空不死 阅读(...) 评论(...) 编辑 收藏