4.15多线程--Park&Unpark

基本使用

它们是 LockSupport 类中的方法

// 暂停当前线程
LockSupport.park();
// 恢复某个线程的运行
LockSupport.unpark(暂停的线程对象);

先 park 再 unpark

public class Demo1 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println(DateUtil.getCurrentTime() + " " + Thread.currentThread().getName() + " start......");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(DateUtil.getCurrentTime() + " " + Thread.currentThread().getName() + " park");
            LockSupport.park();
            System.out.println(DateUtil.getCurrentTime() + " " + Thread.currentThread().getName() + " resume");
        }, "t1");
        t1.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(DateUtil.getCurrentTime() + " " + Thread.currentThread().getName() + " unpark......");
        LockSupport.unpark(t1);
    }
}

特点

与 Object 的 wait & notify 相比

  • wait ,notify,notifyAll 必须配合 Object Monitor 一起使用,而 park unpark 不必
  • park unpark 更精确,以线程为单位来【阻塞】和【唤醒】线程,而 notify notifyAll 只能随机唤醒一个或全部唤醒
  • park unpark 没有调用的先后顺序,而 wait & notify 只能先调 wait 再调 notify

原理

每个线程都有自己的一个 Parker 对象(底层,C语言),由三部分组成_counter,_cond(条件变量),_mutex 。比喻


image.png

image.png
  1. 当前线程调用 Unsafe.park() 方法
  2. 检查_counter,本情况为 0 ,这时,获得 _mutex互斥锁(_mutex 也是一个阻塞队列)
  3. 线程进入 _cond 条件变量阻塞
  4. 设置 _counter = 0(即使原来就是 0 也要设置)

image.png
  1. 调用 Unsafe.unpark(Thread_0)方法,设置 _counter = 1
  2. 唤醒 _cond 条件变量中的 Thread_0
  3. Thread_0 恢复运行
  4. 设置 _counter = 0

image.png
  1. 调用 Unsafe.unpark(Thread_0) 方法,设置 _counter = 1
  2. 当前线程调用 Unsafe.park() 方法
  3. 检查 _counter,本情况为 1,这时线程无需阻塞,继续运行
  4. 设置 _counter = 0

你可能感兴趣的:(4.15多线程--Park&Unpark)