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的源码如下:

Java多线程系列--“JUC锁”07之 LockSupport
  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篇) 

 

你可能感兴趣的:(java多线程)