目录
park&unpark
wait,notify 和 park,unpark的区别
park unpark 原理
先调用park的情况
先调用park,在调用unpark的情况
先调用unpark,在调用park的情况
park&unpark
park和unpark都是LockSupport的方法,park用于暂停当前线程的运行,而unpark用于恢复该线程的运行.
我们看一下代码,来看看park和unpark怎么用?
@Slf4j(topic = "c.TestParkUnPark")
public class TestParkUnPark {
    public static void main(String[] args) throws InterruptedException {
        /**
         * 我们这个unpark既可以在park之前调用,也可以在park之后调用
         * 用来恢复暂停线程的运行
         */
        Thread t1 = new Thread(() -> {
            log.debug("开始");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("park");
            LockSupport.park();//暂停当前线程
            log.debug("resume...");
        },"t1");
        t1.start();
        Thread.sleep(1000);
        log.debug("unPark");
        LockSupport.unpark(t1);//恢复t1线程的运行
    }
} 
先调用park,在调用unpark

先调用unpark在调用park

从这里我们就可以发现与wait和notify不同的一点,就是unpark在park之前调用还是在park之后调用都能唤醒该线程,而在使用wait和notify的时候,先调用notify,后调用wait,那么不会唤醒waitSet中的线程,应为已经错过通知的时间了,不会唤醒.
这里我总结一下wait,notify 和 park,unpark的区别
wait,notify 和 park,unpark的区别
- wait,notify是Object的方法,而park,unpark是LockSupport的方法
 - wait,notify必须北河 Object Monitor一起使用,而park,unpark不需要
 - park&unpark是以线程为单位来[阻塞]和[唤醒]线程的,而notify只能随机唤醒一个等待线程,notifyAll是唤醒所有等待线程,不那么精确.
 - park &unpark 可以先调用unpark,而wait,notify不能先notify.
 
park unpark 原理
每一个线程都有一个parker对象,由三部分组成_counter(标志位),_condition(等待队列),_mutex(对象里面有等待队列)
我们可以打一个比喻.我们把线程当做一个旅游的人,Parker就像他随身携带的背包,条件变量就相当于背包中的帐篷,_counter就相当于背包中的备用干粮
- 调用park 就是要看当前的旅人要不要停下来去休息
 
-  
  
- 如果备用干粮充足(counter为1)那么就不需要停留,继续前进
 - 如果备用干粮耗尽(counter为0)那么就需要去condition帐篷(等待队列)休息
 
 
- 调用unpark,就相当于让干粮(counter重置为1)充足
 
-  
  
- 如果这时旅人还在帐篷中(等待队列condition),那么就唤醒他继续前进
 - 如果这时旅人还在前进,当下次调用park的时候,不休息,仅仅消耗干粮(counter'重置0),不需停留继续前进.
 
 
-  
  
-  
    
- 背包容量有效,多次调用unpark只会补充一份备用干粮
 
 
 -  
    
 
先调用park的情况

先调用park,在调用unpark的情况

先调用unpark,在调用park的情况

总结一下 :
- 如果调用的是park,先会去检查counter
 
-  
  
- 如果counter为0,那么该线程获得互斥锁mutex,去mutex锁对象中的队列_cond中阻塞等待,再将counter置为0
 - 如果counter为1,那么线程无需阻塞,线程继续运行,然后将counter置为0
 
 
- 如果调用的是unpark
 
-  
  
- 如果counter为0,就会将counter置为1,然后唤醒在等待队列中阻塞的线程
 - 如果此时线程还在继续运行,当下次在调用park的时候,检查counter为1,无需停留,继续运行,然后将counter置为0
 
 
另外注意 ,counter只有两种状态0,1多次调用unpark还是为状态还是为1
参考 : 黑马程序员 Java并发编程


















