关于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方法可以设定相应的堵塞时间长度,防止一直堵塞。