关于LockSupport工具类的使用
在阅读aqs源码的时候,经常会看到使用了LockSupport工具类,这个工具类里面提供了两个用于堵塞现线程和解除线程堵塞的接口:
park
unpark
核心源码:
private static void setBlocker(Thread t, Object arg) { // Even though volatile, hotspot doesn't need a write barrier here. UNSAFE.putObject(t, parkBlockerOffset, arg); } /** * Makes available the permit for the given thread, if it * was not already available. If the thread was blocked on * {@code park} then it will unblock. Otherwise, its next call * to {@code park} is guaranteed not to block. This operation * is not guaranteed to have any effect at all if the given * thread has not been started. * * @param thread the thread to unpark, or {@code null}, in which case * this operation has no effect */ 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); } 复制代码
从源码中的构造函数可以看到:
该类是不能够被实例化的。
提供的方法大多数都是静态方法
提供了一些静态成员变量:
// Hotspot implementation via intrinsics API private static final sun.misc.Unsafe UNSAFE; private static final long parkBlockerOffset; private static final long SEED; private static final long PROBE; private static final long SECONDARY; 复制代码
UNSAFE: 工具类
这是一种jdk内部提供的工具类,可以直接操控内存,被jdk广泛用于自己的jar包里面,提供一些对于java来说不安全的功能供java代码调用。让jdk能实现 更多的一些需要用native语言,C或者C++才能实现的功能。
看过Thread源码的朋友应该知道thread里面有一个
volatile Object parkBlocker;
成员变量,这个成员变量主要是提供给LockSupport所使用的。
通过demo测试发现:
LockSupport阻塞和解除阻塞线程直接操作的是Thread,
而Object的wait/notify它并不是直接对线程操作,它是被动的方法,它需要一个object来进行线程的挂起或唤醒。也就是说Thread在进行唤醒操作之后,还需要获取到监视器才可以继续执行。
而LockSupport则不需要。
如果我们将unpark和park的顺序进行调换,结果又会如何呢?
经过测试,不会有影响。反而更加具有灵活性。
线程的中断性测试:
第一种,通过使用interrupt()的方式来进行线程中断:
结果并没有实际的效果,因为interrupt()只不过是将线程的中断状态进行设置调整罢了。并没有进行完整的中断。因此需要加入一个开关来进行中断处理:
/** * @author idea * @data 2019/2/1 */ public class Demo2 implements Runnable{ public static void main(String[] args) throws InterruptedException { Thread testThread=new Thread(new Demo2(),"InterruptionInJava"); testThread.start(); Thread.sleep(1000); //对该线程进行中断测试 testThread.interrupt(); System.out.println("end"); } @Override public void run() { while(true){ if(!Thread.currentThread().isInterrupted()){ System.out.println("this is a test!"); }else{ break; } } } } 复制代码
如果遇到了类似于下图中的这种情况:线程堵塞
interrupt函数可以提供将该线程进行中断的处理,不过可能会有相应的异常抛出。
parkBlockerOffset是unsafe包里面的一个成员变量。由于目标线程可能是处于堵塞状态,因此想要获取相应的对象,需要通过一个parkBlockerOffset的内存偏移量来获取对象信息。
LockSupport中的park方法可以设定相应的堵塞时间长度,防止一直堵塞。