Java 多线程park unpark 原理

介绍:park unpark 与wait、notify很像,但是park unpark是属于每个线程私有的,而wait、notify是属于Object对象的,相同的就是两者调用后都会进入WAIT状态,没去唤醒的话就一直等待下去。park 对象由三部分组成_counter,_cond,-mutex
看一个例子来说明:

public static void main(String[] args) { 

        Thread t1 = new Thread(() -> { 
            log.debug("start...");
            sleep(1);
            log.debug("park...");
            LockSupport.park();
            log.debug("resume...");
        }, "t1");
        t1.start();

        sleep(2);
        log.debug("unpark...");
        LockSupport.unpark(t1);
    }

输出:

当t1线程执行到LockSupport.park();

此时当前线程会去调用.park() ,检查park对象的_counter是否为0,如果等于0,将获取_mutex互斥锁,则该线程进入_cound堵塞,此时的_counter仍然为0

当main线程执行到LockSupport.unpark(t1);

counter会被设置为1,然后唤醒_cond堵塞的线程,使其继续执行,如果被unpark多次,counter值只会被设置一次。

反过来看另外一个例子:

public static void main(String[] args) { 

        Thread t1 = new Thread(() -> { 
            log.debug("start...");
            sleep(2);
            log.debug("park...");
            LockSupport.park();
            log.debug("resume...");
        }, "t1");
        t1.start();

        sleep(1);
        log.debug("unpark...");
        LockSupport.unpark(t1);
    }

输出:

结果是不是挺意外的,的确如此,这就是unpark、park与wait、notyfy很大区别的一种。

主线程先醒过来然后去unpark,然后再去park,发现已经park不上去了。我们之前的如果没有wait就去notify会报java.lang.IllegalMonitorStateException

上面的例子主线程执行到LockSupport.unpark(t1);

t1的park对象_counter值被设置为1

t1线程会检查状态是否为1,如果为1这时候线程无需堵塞,继续运行,最后还会把counter设置为0。

页面下部广告