java并发编程的艺术(7)LockSupport

关于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;
            }
        }
    }
}

如果遇到了类似于下图中的这种情况:线程堵塞
java并发编程的艺术(7)LockSupport
interrupt函数可以提供将该线程进行中断的处理,不过可能会有相应的异常抛出。

parkBlockerOffset是unsafe包里面的一个成员变量。由于目标线程可能是处于堵塞状态,因此想要获取相应的对象,需要通过一个parkBlockerOffset的内存偏移量来获取对象信息。
LockSupport中的park方法可以设定相应的堵塞时间长度,防止一直堵塞。