天天看点

Java并发编程札记-(四)JUC锁-06LockSupport

LockSupport是JUC锁中比较基础的类,用来创建锁和其他同步类的基本线程阻塞原语。比如,在AQS中就使用LockSupport作为基本线程阻塞原语。它的park()和unpark()方法分别用于阻塞线程和解除阻塞线程。与Thread.suspend()相比,它没有由于resume()在前发生,导致线程无法继续执行的问题。和Object.wait()对比,它不需要先获得某个对象的锁,能够响应中断请求(中断状态被设置成true),也不会抛出InterruptException异常。

函数列表

//方法摘要
static Object   getBlocker(Thread t) 
          //返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null。
static void park() 
          //为了线程调度,禁用当前线程,除非许可可用。
static void park(Object blocker) 
          //为了线程调度,在许可可用之前禁用当前线程。
static void parkNanos(long nanos) 
          //为了线程调度禁用当前线程,最多等待指定的等待时间,除非许可可用。
static void parkNanos(Object blocker, long nanos) 
          //为了线程调度,在许可可用前禁用当前线程,并最多等待指定的等待时间。
static void parkUntil(long deadline) 
          //为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
static void parkUntil(Object blocker, long deadline) 
          //为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
static void unpark(Thread thread) 
          //如果给定线程的许可尚不可用,则使其可用。
           

许可

此类以及每个使用它的线程与一个许可关联。如果许可可用,当前线程可获取许可执行。如果许可不可用,调用park()后,当前线程阻塞,等待获取许可。unpark(Thread thread)可使指定线程的许可可用。这与Semaphore相似,但LockSupport最多只能有一个许可。

运行如下代码:

public static void main(String[] args) {
    LockSupport.park();
    System.out.println("helloworld");
}
           

会发现线程一直处于阻塞状态,helloworld一直打印不出啦。说明LockSupport.park();执行时,许可是不可用的。这说明许可默认是不可用的。

再执行如下代码;

public static void main(String[] args) {
    Thread thread = Thread.currentThread();  
    LockSupport.unpark(thread);
    LockSupport.park();
    System.out.println("helloworld");
}
           

会发现helloworld打印出来了。这印证了上面的结论。

blocker

三种形式的park(park(Object blocker)、parkNanos(Object blocker, long nanos)、parkUntil(Object blocker, long deadline))都支持blocker对象参数。此对象在线程受阻塞时被记录,以允许监视工具和诊断工具确定线程受阻塞的原因。监视工具和诊断工具可以使用方法getBlocker(java.lang.Thread)访问 blocker。建议最好使用这些形式,而不是不带此参数的原始形式。在锁实现中提供的作为blocker的普通参数是this。

响应中断

Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "阻塞了");
            LockSupport.park();
            if (Thread.interrupted()) {
                System.out.println(Thread.currentThread().getName() + "中断了");

            }
            System.out.println(Thread.currentThread().getName() + "运行了");

        }
    });
    t.start();
    t.interrupt();
}
           

运行结果:

Thread-阻塞了
Thread-中断了
Thread-运行了
           

说明线程如果因为调用park而阻塞的话,能够响应中断请求(中断状态被设置成true),不会抛出InterruptedException。

如果将

LockSupport.park();

替换为wait(),且给run()加锁,

Thread t = new Thread(new Runnable() {
            @Override
            public synchronized void run() {
                System.out.println(Thread.currentThread().getName() + "阻塞了");
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (Thread.interrupted()) {
                    System.out.println(Thread.currentThread().getName() + "中断了");

                }
                System.out.println(Thread.currentThread().getName() + "运行了");
            }
        });
        t.start();
        t.interrupt();
           

运行结果:

Thread-阻塞了
java.lang.InterruptedException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Unknown Source)
    at com.thread.locksupport.ParkTest3$run(ParkTest.java:)
    at java.lang.Thread.run(Unknown Source)
Thread-运行了
           

说明,和Object.wait()对比,LockSupport不需要先获得某个对象的锁,能够响应中断请求(中断状态被设置成true),也不会抛出InterruptException异常。

源码

待补充

本文就讲到这里,想了解Java并发编程更多内容请参考:

  • Java并发编程札记-目录