LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程
1 LockSupport类介绍 LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程。主要是通过park()和unpark(thread)方法来实现阻塞和唤醒线程的操作的。
每个线程都有一个许可(permit),permit只有两个值1和0,默认是0。
当调用unpark(thread)方法,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,permit值还是1)。
当调用park()方法,如果当前线程的permit是1,那么将permit设置为0,并立即返回。如果当前线程的permit是0,那么当前线程就会阻塞,直到别的线程将当前线程的permit设置为1.park方法会将permit再次设置为0,并返回。
注意:因为permit默认是0,所以一开始调用park()方法,线程必定会被阻塞。调用unpark(thread)方法后,会自动唤醒thread线程,即park方法立即返回。
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()和unpark()不会遇到“Thread.suspend 和 Thread.resume所可能引发的死锁”问题。
因为park() 和 unpark()有许可的存在;调用 park() 的线程和另一个试图将其 unpark() 的线程之间的竞争将保持活性。
2 基本用法 LockSupport 很类似于二元信号量(只有1个许可证可供使用),如果这个许可还没有被占用,当前线程获取许可并继 续 执行;如果许可已经被占用,当前线 程阻塞,等待获取许可。
1 2 3 4 5 public static void main (String[] args) { LockSupport.park(); System.out.println("block." ); }
运行该代码,可以发现主线程一直处于阻塞状态。因为 许可默认是被占用的 ,调用park()时获取不到许可,所以进入阻塞状态。
如下代码:先释放许可,再获取许可,主线程能够正常终止。LockSupport许可的获取和释放,一般来说是对应的,如果多次unpark,只有一次park也不会出现什么问题,结果是许可处于可用状态。
1 2 3 4 5 6 7 public static void main (String[] args) { Thread thread = Thread.currentThread(); LockSupport.unpark(thread); LockSupport.park(); System.out.println("b" ); }
LockSupport是可不重入 的,如果一个线程连续2次调用 LockSupport .park(),那么该线程一定会一直阻塞下去。
1 2 3 4 5 6 7 8 9 10 11 12 public static void main (String[] args) throws Exception { Thread thread = Thread.currentThread(); LockSupport.unpark(thread); System.out.println("a" ); LockSupport.park(); System.out.println("b" ); LockSupport.park(); System.out.println("c" ); }
这段代码打印出a和b,不会打印c,因为第二次调用park的时候,线程无法获取许可出现死锁。
下面我们来看下LockSupport对应中断的响应性
1 2 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 32 33 34 35 36 public static void t2 () throws Exception { Thread t = new Thread(new Runnable() { private int count = 0 ; @Override public void run () { long start = System.currentTimeMillis(); long end = 0 ; while ((end - start) <= 1000 ) { count++; end = System.currentTimeMillis(); } System.out.println("after 1 second.count=" + count); LockSupport.park(); System.out.println("thread over." + Thread.currentThread().isInterrupted()); } }); t.start(); Thread.sleep(2000 ); t.interrupt(); System.out.println("main over" ); }
最终线程会打印出thread over.true。这说明 线程如果因为调用park而阻塞的话,能够响应中断请求(中断状态被设置成true),但是不会抛出InterruptedException 。
3 LockSupport函数列表* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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)
4 LockSupport示例 对比下面的“示例1”和“示例2”可以更清晰的了解LockSupport的用法。
示例1
1 2 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 32 33 34 35 36 public class WaitTest1 { public static void main (String[] args) { ThreadA ta = new ThreadA("ta" ); synchronized (ta) { try { System.out.println(Thread.currentThread().getName()+" start ta" ); ta.start(); System.out.println(Thread.currentThread().getName()+" block" ); ta.wait(); System.out.println(Thread.currentThread().getName()+" continue" ); } catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadA extends Thread { public ThreadA (String name) { super (name); } public void run () { synchronized (this ) { System.out.println(Thread.currentThread().getName()+" wakup others" ); notify(); } } } }
示例2
1 2 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 32 33 34 35 import java.util.concurrent.locks.LockSupport; public class LockSupportTest1 { private static Thread mainThread; public static void main (String[] args) { ThreadA ta = new ThreadA("ta" ); mainThread = Thread.currentThread(); System.out.println(Thread.currentThread().getName()+" start ta" ); ta.start(); System.out.println(Thread.currentThread().getName()+" block" ); LockSupport.park(mainThread); System.out.println(Thread.currentThread().getName()+" continue" ); } static class ThreadA extends Thread { public ThreadA (String name) { super (name); } public void run () { System.out.println(Thread.currentThread().getName()+" wakup others" ); LockSupport.unpark(mainThread); } } }
运行结果
1 2 3 4 main start ta main block ta wakup others main continue
说明:park和wait的区别。wait让线程阻塞前,必须通过synchronized获取同步锁。
5 LockSupport源码注释 1 2 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 package java.util.concurrent.locks;import sun.misc.Unsafe;import java.util.concurrent.Semaphore;import java.util.concurrent.ThreadLocalRandom;public class LockSupport { private LockSupport () {} private static void setBlocker (Thread t, Object arg) { UNSAFE.putObject(t, parkBlockerOffset, arg); } public static void unpark (Thread thread) { if (thread != null ) UNSAFE.unpark(thread); } public static void park (Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false , 0L ); setBlocker(t, null ); } public static void parkNanos (Object blocker, long nanos) { if (nanos > 0 ) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false , nanos); setBlocker(t, null ); } } public static void parkUntil (Object blocker, long deadline) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(true , deadline); setBlocker(t, null ); } public static Object getBlocker (Thread t) { if (t == null ) throw new NullPointerException(); return UNSAFE.getObjectVolatile(t, parkBlockerOffset); } public static void park () { UNSAFE.park(false , 0L ); } public static void parkNanos (long nanos) { if (nanos > 0 ) UNSAFE.park(false , nanos); } public static void parkUntil (long deadline) { UNSAFE.park(true , deadline); } static final int nextSecondarySeed () { int r; Thread t = Thread.currentThread(); if ((r = UNSAFE.getInt(t, SECONDARY)) != 0 ) { r ^= r << 13 ; r ^= r >>> 17 ; r ^= r << 5 ; } else if ((r = ThreadLocalRandom.current().nextInt()) == 0 ) r = 1 ; UNSAFE.putInt(t, SECONDARY, r); return r; } private static final Unsafe UNSAFE; private static final long parkBlockerOffset; private static final long SEED; private static final long PROBE; private static final long SECONDARY; static { try { UNSAFE = Unsafe.getUnsafe(); Class<?> tk = Thread.class; parkBlockerOffset = UNSAFE.objectFieldOffset (tk.getDeclaredField("parkBlocker" )); SEED = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomSeed" )); PROBE = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomProbe" )); SECONDARY = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomSecondarySeed" )); } catch (Exception ex) { throw new Error(ex); } } }