1. 方法概述

LokSupport 包含以下方法

void park();
void park(Object blocker);
void parkNanos(long nanos);
void parkNanos(Object blocker, long nanos);
void parkUntil(long deadline);
void parkUntil(Object blocker, long deadline);
void unpark(Thread thread);
  • blocker 我们一般传递 this ,没啥实际作用。这个阻塞对象会出现在线程 dump 中,方便我们分析问题。
  • parkNanos 可以指定最大堵塞时间, 纳秒
  • partUntil 参数是一个绝对值,等待到什么时候

2. 使用例子

import java.util.concurrent.locks.LockSupport;

class Solution {
    public static void main(String[] args) {
        Thread comsumer = new Thread(() -> {
            while (true) {
                System.out.println("等待包子");
                LockSupport.park();
                System.out.println("吃上包子");
                System.out.println("------------");
            }
        });
        comsumer.start();

        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("包子做好了");
                LockSupport.unpark(comsumer);
            }
        }).start();
    }
}

3. 和 Thread.sleep 的区别

  1. 从功能上来说,Thread.sleep() 和 LockSupport.park() 方法类似,都是阻塞当前线程的执行,且都不会释放当前线程占有的锁资源
  2. Thread.sleep() 没法从外部唤醒,只能自己醒过来,LockSupport.park() 方法可以被另一个线程调用 LockSupport.unpark() 方法唤醒;
  3. Thread.sleep() 方法声明上抛出了 InterruptedException 中断异常,所以调用者需要捕获这个异常或者再抛出,LockSupport.park()方法不需要捕获中断异常;
  4. Thread.sleep() 本身就是一个 native 方法;
  5. LockSupport.park() 底层是调用的 Unsafe 的 native 方法;

4. 和 wait() 的区别

  1. Object.wait() 方法需要在 synchronized 块中执行;LockSupport.park()可以在任意地方执行;
  2. Object.wait() 方法声明抛出了中断异常,调用者需要捕获或者再抛出;
  3. LockSupport.park() 不需要捕获中断异常
  4. Object.wait() 不带超时的,需要另一个线程执行 notify() 来唤醒,但不一定继续执行后续内容;
  5. LockSupport.park() 不带超时的,需要另一个线程执行 unpark() 来唤醒,一定会继续执行后续内容;
  6. 如果在wait()之前执行了 notify(),会抛出 IllegalMonitorStateException 异常;
  7. 如果在 park() 之前执行了 unpark() ,线程不会被阻塞,直接跳过park(),继续执行后续内容;
功能点精准控制执行顺序中断
wait/notify挂起:指定当前线程挂起

唤醒:随机唤醒 1 个线程或全部唤醒
执行顺序需要严格保证 wait操作发生在 notify之前,如果 notifywait之前执行了,那么 wait操作将进入无限等待的窘境响应中断,且需处理编译期异常
park/unpark挂起:指定当前线程挂起

唤醒:精确唤醒指定的 1 个线程

注:虽然唤醒可指定某线程,但挂起操作只会针对当前线程生效,因为当前线程并不了解被挂起线程的真实状态,如果一旦可操控,势必会带来不可预期的安全问题
unpark操作可发生在 park之前,但仅会生效一次;例如针对线程A首先执行了2次 unpark操作,然后对A第1次执行 park操作时不会有阻塞,但第2次执行 park时会进入等待响应中断,但不抛出异常,发生中断后,park()方法会自动结束,通过 Thread.interrupted()来判断是中断还是 unpark()导致的