java并发编程(十一)LockSupport之park/unpark

一、简介

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()流程
park() (1).png

如上图所示,有线程thread1:

1、执行park()方法

2、检查_counter是否是0

3、如果_counter是0,则获取互斥锁_mutex

4、获取到互斥锁,进入_cond中进行阻塞

5、再次设置_counter为0

  • unpark()流程
unpark().png

如上图所示,有线程thread1:

1、执行unpark(thread-1),设置_counter=1
2、唤醒_cond中阻塞的线程thread-1
3、线程thread-1恢复运行
4、再次设置_counter = 0

  • 先unpark(),再park()流程
先进行unpark(),再park().png

如上图所示,有线程thread-1

1、调用unpark(thread-1),设置_counter为1

2、调用park()

3、检查_counter是否为0,此时为1,不阻塞,继续运行

4、最后设置_counter为0

你可能感兴趣的:(java并发编程(十一)LockSupport之park/unpark)