首页 > 技术文章 > LockSupport中的park()与unpark()

wkynf 2020-12-06 12:04 原文

类注释原文:Basic thread blocking primitives for creating locks and other synchronization classes.
意思就是LockSupport类用于创建锁和其他同步类的基本线程阻塞原语。

LockSupport是基于Unsafe实现的提供的两个主要方法就是park()和unpark()。
其中park()方法我们可以理解为阻塞,等待,挂起,而unpark()我们理解为唤醒,恢复。

park()方法和unpark()方法解释。

LockSupport是其他同步类的及基本线程阻塞原语,所以并不需要获取对象的监视器,而是给线程一个“许可”(permit)。而每个线程的permit只能是0个或者1个。

unpark会给线程一个permit,而且最多是1;而park会消耗一个permit并返回,如果线程没有permit则会阻塞。(默认情况下permit的数量为0,也就是如果直接调用park方法的话,会被直接阻塞的。)


下面我们将对照着源码注释和代码示例对比一下我们的理解是否正确。

park()

原文注释:

/**
* Disables the current thread for thread scheduling purposes unless the
* permit is available.
*
* <p>If the permit is available then it is consumed and the call
* returns immediately; otherwise the current thread becomes disabled
* for thread scheduling purposes and lies dormant until one of three
* things happens:
*
* <ul>
*
* <li>Some other thread invokes {@link #unpark unpark} with the
* current thread as the target; or
*
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread; or
*
* <li>The call spuriously (that is, for no reason) returns.
* </ul>
*
*/


上面是park()方法的注释,什么意思呢?
意思就是除非线程允许,否则禁用当前线程以进行线程调度。如果有许可(permit)的话,则将其消耗掉,并且立即返回;否则,出于线程调度的目的,当前线程将被禁用并处于休眠状态,

直到发生以下三种情况之一:

(1):其他线程将当前线程作为目标调用unpark方法;

(2):其他线程interrupt interrupts中断当前线程;

(3):调用无条件返回

unpark(Thread thread)

* Makes available the permit for the given thread, if it
* was not already available. If the thread was blocked on
* {@code park} then it will unblock. Otherwise, its next call
* to {@code park} is guaranteed not to block. This operation
* is not guaranteed to have any effect at all if the given
* thread has not been started.

 如果thread线程不可用,则使该线程可用并给他一个许可(permit),。

如果thread线程在被阻止,则它将取消阻止。否则,将确保其对下一次调用park()不会阻塞。

如果给定线程尚未启动,则此操作根本无法保证会产生任何效果。

 

下面我们就用代码测试一下上面的结论:

(1)直接调用park()会被阻塞

public class TestLockSupport {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            System.out.println("进入" + Thread.currentThread().getName());
            LockSupport.park();
            System.out.println(Thread.currentThread().getName()+":"+"block");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName()+":"+"unblock");
        },"线程1");
        t1.start();
    }
}

 

 

 只执行了 System.out.println("进入" + Thread.currentThread().getName());说明后面的被阻塞了。

(2)直接调用unpark()会解除阻塞

public class TestLockSupport {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            System.out.println("进入" + Thread.currentThread().getName());
            LockSupport.park();
            System.out.println(Thread.currentThread().getName()+":"+"block");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName()+":"+"unblock");
        },"线程1");

        t1.start();
        LockSupport.unpark(t1);
        Thread.sleep(1000);
        LockSupport.unpark(t1);
    }
}

 

 

三次输出都执行了,说明unpark()起作用了。

 (3)每个线程最多有一个permit

public class TestLockSupport {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("进入" + Thread.currentThread().getName());
            LockSupport.park();
            System.out.println(Thread.currentThread().getName()+":"+"block");
            LockSupport.park();
            System.out.println(Thread.currentThread().getName()+":"+"unblock");
        },"线程1");

        t1.start();
        LockSupport.unpark(t1);
        LockSupport.unpark(t1);
        LockSupport.unpark(t1);
        LockSupport.unpark(t1);
        LockSupport.unpark(t1);
    }
}

 

 

在线程t1执行LockSupport.park();之前多次执行了 LockSupport.unpark(t1);,但是最后 System.out.println(Thread.currentThread().getName()+":"+"unblock");没有执行,说明permit的数量只有一个。

 

推荐阅读