目录
一、基本使用
二、特点(与 wait/notify 对比)
三、park & unpark 的原理
一、基本使用
1. park 和 unpark 是 LockSupport 中的方法
2. LockSupport.park();// 暂停线程,线程进入 WAIT 状态
3. LockSupport.unpark(被暂停的线程);// 恢复被暂停线程的运行
二、特点(与 wait/notify 对比)
1. park/unpark 既可以在线程被 park 之后调用,也可以在 park 之前调用,都可以恢复线程的运行;wait/notify 只能先 wait 再 notify
2. wait/notify 需要配合 Object Monitor 来使用,park/unpark 不需要
3. park/unpark 是以线程为单位,而 notify 只能随机唤醒 Monitor 上的一个等待线程,notifyAll 是唤醒所有等待线程,没有 park/unpark 精确
三、park & unpark 的原理
park 和 unpark 底层是 C 实现的,Java 层面看不到
1. 介绍:每个线程都会关联一个 Parker 对象,由三部分组成 _counter、_cond 和 _mutex,_counter 为 1 表示不需要阻塞可以继续运行,_counter 为 0 表示需要进入 _cond 阻塞,要等到 unpark 将 _counter 设置为 1 之后才能运行
- park():检查 counter 的状态,如果是 0,当前线程就进入 condition 阻塞,如果是 1,说明不需要阻塞,可以继续运行,同时将 counter 设置为 1
- unpark():将 counter 状态设置为 1,判断线程是否在 cond 中阻塞,如果在则唤醒它继续执行,唤醒之后将 counter 重新设置为 0;如果线程处于运行状态时调用 unpark,当下次调用 park 进行阻塞时就不会被阻塞,而是继续运行(因为 park 先检查发现 counter 是 1,所以不会进入 cond)
2. park
- 当前线程调用 Unsafe.park() 方法
- 检查 counter 为 0(没调用 unpark,初始为 0),获取 mutex 互斥锁
- 进入 cond 条件变量阻塞
- 设置 counter 为 0
3. 先 park 再 unpark 的 unpark
- 调用 Unsafe.unpark(Thread_0) 方法,设置 counter 为 1
- 唤醒 cond 条件变量中的 Thread_0
- Thread_0 恢复运行
- 设置 counter 为 0
4. 先 unpark 再 park 的 unpark
- 调用 Unsafe.unpark(Thread_0) 方法,设置 counter 为 1
- 调用 Unsafe.park()
- 检查 counter 发现是 1,无需阻塞,Thread_0 继续运行
- 设置 counter 为 0
如果之后调用 park,还是会被阻塞,因为上次调用 park 之后 counter 已经设置成了 0,需要再次的 unpark 将 counter 设置为 1 唤醒线程才能继续运行