java并发编程(十一)LockSupport之park/unp
一、简介
1.1 主要方法
Park/UnPark方法是LockSupport当中的方法。
其常用方法有如下:
-
park():暂停当前线程。
-
park(Object blocker):暂停当前线程,并指定负责此线程停放的同步对像。
-
parkNanos(long nanos):暂停当前线程,指定等待的最大纳秒数。
-
parkNanos(Object blocker, long nanos):暂停当前线程,指定等待的最大纳秒数和负责此线程停放的同步对像。
-
parkUntil(long deadline):暂停当前线程,指定暂停到的时间点。
-
parkUntil(long deadline):暂停当前线程,指定暂停到的时间点和负责此线程停放的同步对像。
-
unpark(Thread thread):恢复某个线程的运行。
线程可再次运行的条件,这里根据上面的park()方法对号入座:
- 有线程调用unpark方法
- 指定等待时间过时
- 指定的截止日期过时
- 其他线程中断当前线程
1.2 优势
与 Object 的 wait/notify 相比:
- wait,notify 和 notifyAll 必须配合 Monitor(重量级锁) 一起使用,而 park,unpark 不必。
- park/unpark 是以线程为单位来阻塞和唤醒线程,而 notify 只能随机唤醒一个等待线程,notifyAll是唤醒所有等待线程,无法做到精确唤醒。
- park/unpark 可以先 unpark,而 wait/notify 不能先 notify。
二、原理
常见的方式有:
- 先park(),再unpark()
- 先unpark(),再park()
上面两种方式造成的结果是不同的:
- 先park(),再unpark():线程会阻塞,unpark后继续执行。
- 先unpark(),再park():线程不会阻塞,park后仍然可以继续执行。
下面我们来看下具体时间如何实现的,这两个方法的底层都是native的,我们看不见实现过程,所以下面直接归纳整理出原理及设计到的变量,理解就好。
在底层实现中,每个线程都有自己的一个 Parker 对象,由三部分组成 _counter , _cond 和 _mutex。
简单描述下:_counter就是是否阻塞的标记 , _cond就好比阻塞后线程的容器, _mutex是互斥锁,线程需持有后进入_cond中。
- park()流程
如上图所示,有线程thread1:
1、执行park()方法
2、检查_counter是否是0
3、如果_counter是0,则获取互斥锁_mutex
4、获取到互斥锁,进入_cond中进行阻塞
5、再次设置_counter为0
- unpark()流程
如上图所示,有线程thread1:
1、执行unpark(thread-1),设置_counter=1
2、唤醒_cond中阻塞的线程thread-1
3、线程thread-1恢复运行
4、再次设置_counter = 0
- 先unpark(),再park()流程
如上图所示,有线程thread-1
1、调用unpark(thread-1),设置_counter为1
2、调用park()
3、检查_counter是否为0,此时为1,不阻塞,继续运行
4、最后设置_counter为0