并发编程(五)LockSupport

并发编程(五)LockSupport

LockSupport 提供 park() 和 unpark() 方法实现阻塞线程和解除线程阻塞,实现的阻塞和解除阻塞是基于“许可(permit)”作为关联,permit 相当于一个信号量(0,1),默认是0。 线程之间不再需要一个 Object 或者其它变量来存储状态,不再需要关心对方的状态。

一、LockSupport API

(1) pack

方法 说明
park() 挂起当前线程
park(Object blocker) 挂起当前线程
parkNanos(long nanos) 指定挂起时间(相对于当前的时间),时间到后自动被唤醒
parkNanos(Object blocker, long nanos) 指定挂起时间(相对于当前的时间)
parkUntil(long deadline) 指定挂起时间(绝对时间),时间到后自动被唤醒
parkUntil(Object blocker, long deadline) 指定挂起时间(绝对时间),时间到后自动被唤醒

从上面表格可以看出,park 支持 blocker 对象作为参数,该字段是 Thread 类,专门为 LockSupport 而设计的。此 blocker 对象在线程受阻塞时被记录,这样监视工具和诊断工具就可以确定线程受阻塞的原因。建议最好使用这些带 blocker 的方法版本,而不是不带 blocker 参数的方法。

public static void park() {
    UNSAFE.park(false, 0L);
}

(2) unpark

设置线程许可为可用。

  • 如果线程当前已经被 pack 挂起,那么这个线程将会被唤醒。
  • 如果线程当前没有被挂起,那么下次调用 pack 不会挂起线程。
public static void unpark(Thread thread) {
    if (thread != null)
        UNSAFE.unpark(thread);
}

二、LockSupport 使用

(1) 先park后unpark

public void test1() throws Exception {
    Thread mainThread = Thread.currentThread();
    Thread thread = new Thread(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("before unpark, " + LockSupport.getBlocker(mainThread));
        LockSupport.unpark(mainThread);
        System.out.println("after unpark, " + LockSupport.getBlocker(mainThread));
    });
    thread.start();
    System.out.println("before park");
    // 等待获取许可
    LockSupport.park("Park");
    System.out.println("after park");
}

结果:

before park
before unpark, Park
after park
after unpark, null

(2) 先unpark后unpark

先执行 unpark,在调用 park,直接就没被阻塞, 因此 park/unpark 相比 wait/notify 更加的灵活

public void test2() throws Exception {
    Thread mainThread = Thread.currentThread();
    Thread thread = new Thread(() -> {
        System.out.println("before unpark, " + LockSupport.getBlocker(mainThread));
        LockSupport.unpark(mainThread);
        System.out.println("after unpark, " + LockSupport.getBlocker(mainThread));
    });
    thread.start();

    TimeUnit.SECONDS.sleep(1);
    System.out.println("before park");
    // 等待获取许可
    LockSupport.park("Park");
    System.out.println("after park");
}

(2) park与interrupt

public void test3() throws Exception {
    Thread thread = new Thread(() -> {
        System.out.println(Thread.currentThread().isInterrupted()); // false
        LockSupport.park();
        System.out.println(Thread.currentThread().isInterrupted()); // true
    });
    thread.start();

    TimeUnit.SECONDS.sleep(1);
    thread.interrupt();
    System.in.read();
}

简而言之:

  1. 实现机制和 wait/notify 有所不同,面向的是线程
  2. 不需要依赖监视器
  3. 与 wait/notify 没有交集
  4. 使用起来方便灵活

参考:

  1. 《LockSupport解析与使用》:https://blog.csdn.net/secsf/article/details/78560013

每天用心记录一点点。内容也许不重要,但习惯很重要!

猜你喜欢

转载自www.cnblogs.com/binarylei/p/10074774.html