park和unpark方法详解
基于许可的多线程控制介绍
为了控制多个线程访问共享资源 ,我们需要为每个访问共享区间的线程派发一个许可。拿到一个许可的线程才能进入共享区间活动。当线程完成工作后,离开共享区间时,必须要归还许可,以确保后续的线程可以正常取得许可。如果许可用完了,那么线程进入共享区间时,就必须等待,这就是控制多线程并行的基本思想。
park和unpark方法
park和unpark方法是工具类LockSuppor介绍t中的API,它的作用很简单,就是挂起和继续执行线程。
public static void park() // 表示让线程暂停
public static void unpark(Thread thread) // 表示让线程继续执行,恢复 暂停线程对象的运行
关于park和unpark方法执行先后顺序
LockSupport.unpark(Thread.currentThread());
LockSupport.park();
在park()之前,先执行了unpark(),进而释放了一个许可,也就是说当前线程有一个可用的许可。而park()在有可用许可的情况下,是不会阻塞线程的。
LockSupport.park();
LockSupport.unpark(Thread.currentThread());
先执行park(),获取许可证,然后执行unpark()释放了一个许可,并不会发生线程阻塞。
park()和unpark()的执行效果和它调用的先后顺序没有关系。这一点相当重要,因为在一个多线程的环境中,我们往往很难保证函数调用的先后顺序(都在不同的线程中并发执行),因此,这种基于许可的做法能够最大限度保证程序不出错。
与Object的wait和notify对比
wait,notify 和 notifyAll 必须配合 Object Monitor 一起使用,而 park,unpark 不必
park & unpark 是以线程为单位来阻塞和唤醒线程,而 notify 只能随机唤醒一个等待线程,notifyAll是唤醒所有等待线程,就不那么【精确】
park & unpark 可以先 unpark,而 wait & notify 不能先 notify
park和unpark原理
park和unpark会调用Unsafe类中的native方法
每个线程都会和一个park对象关联起来,由三部分组成 _counter , _cond 和 _mutex。核心部分是counter,我们可以理解为一个标记位。
当调用park时会看counter是否为0,为0则进入阻塞队列。为1则继续运行并将counter置为0。
当调用unpark时,会将counter置为1,若之前的counter值为0,还唤醒阻塞的线程。