park和unpark原理,希望大佬进来看看为什么!!!

park 和 unpark

park和unpark是LockSupport里面的方法,park的中文翻译有停在这的意思,所以park方法的作用就是停下一个线程,而unpark就是唤醒线程。

特点

与Object的wait&notify相比

  • wait和notify相比必须配合Object Monitor一起使用,而park,unpark则不用
  • park&unpark是以线程为单位来阻塞和唤醒线程的,而notify只能随机唤醒一个,notifyAll只能唤醒所有,不怎么精确
  • park&unpark是可以先unpark的类似于先打个预防针,而wait&notify则不能

原理

每个线程都有自己的一个Parker对象(是由底层c++代码实现的),由三部分组成_counter , _coud , _mutex 。

其中我们重点关心的是_counter,其中只有两种值0,1。

看个例子:

Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                log.debug("开始");
                LockSupport.park();
                log.debug("他解开了...");
                LockSupport.park();
                log.debug("结束");
            }
        }, "t1");
        t1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LockSupport.unpark(t1);
        try {
            Thread.sleep(1000); //再睡一秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LockSupport.unpark(t1);
复制代码

在这段代码中我们两次停下了t1线程,又两次解开了。我们注意到,第二次unpark之前我们又睡了一秒,因为在之前我直接连续执行两次unpark。但并没有t1线程第二次启动。所以我去探寻了原因。

在黑马程序员中的课中是这么解释的:

image.png

在线程处于runnable的场景下,我们调用park方法的时候,线程会去看Parker对象中的_counter的值,如果为0则进入mutex中的cond队列中阻塞。如上图。

如果此时的_counter的值已经为1了则不会进入阻塞,但会使counter的值消耗变为0。这就是他可以提前unpark的原因。相当于一个预防针。

而当调用unpark的方法的时候就是把counter的值变为1。然后告诉线程可以出来了,线程就会继续运行同时把counter的值消耗变为0。

但是对于此我还是有很多不解,例如连续用两次unpark并不会像打预防针一样防止了线程第二次park被阻塞。

例如这样:

Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                log.debug("开始");
                LockSupport.park();
                log.debug("他解开了...");
​
                LockSupport.park();
                log.debug("结束");
            }
        }, "t1");
        t1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LockSupport.unpark(t1);
        LockSupport.unpark(t1);
复制代码

但是只要在unpark之间加入一段sleep哪怕时间很短也可以,都可以让起到预防针或者二次唤醒的作用。

想要知道为什么还是要继续深入学习,或者哪位大佬看到之后可以评论器教学一下,表示感谢!

猜你喜欢

转载自juejin.im/post/7102322027335254046