LockSupport
标签:Java并发

LockSupport

LockSupport是一个非常好用的的线程阻塞的工具类,它可以在线程内任意位置让线程阻塞。

LockSupport提供了park()方法用于阻塞当前线程,类似的还有parkNanos()、parkUtil()等

一个简单的示例

public class LockSupportDemo {
    public static Object u=new Object();
    public static ChangeObjectThread t1=new ChangeObjectThread("t1");
    public static ChangeObjectThread t2=new ChangeObjectThread("t2");
    public static class ChangeObjectThread extends Thread{
        public ChangeObjectThread(String name){
            super.setName(name);
        }

        @Override
        public void run() {
            synchronized (u){
                System.out.println("in "+getName());
                LockSupport.park();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        t1.start();
        Thread.sleep(1000);
        t2.start();
        LockSupport.unpark(t1);
        LockSupport.unpark(t2);
        t1.join();
        t2.join();
    }
}

虽然我们没有办法保证unpark()方法一定在park()方法之后执行,但是可以正常执行完毕。这是因为LockSupport采用类似信号量(Semaphore)的机制。它会为每个线程准备一个许可(permit),如果许可可用的话,那么park()方法将会消费这个许可,即将该许可变为不可用,然后方法立即返回。如果许可不可用的话,那么将会发生阻塞。而unpark()方法则是让许可变得可用。但许可只会有一个,不能像Semaphore那样存在多个。

上面这个机制使得就算unpark方法发生在park方法之前,也只是将许可变得可用,接下来的park仍然可以操作完后返回。

而且park()方法执行后,会让线程的状态变成WAITING,而且会标注出来是由与park()引起的。


再来说一下LockSupport的中断

park()支持响应中断,但是它并不会抛出异常,而是直接返回,但是我们可以从Thread.interrupted()方法中获得中断标记

public class LockSupportIntDemo {
    public static Object u=new Object();
    public static ChangeObjectThread t1=new ChangeObjectThread("t1");
    public static ChangeObjectThread t2=new ChangeObjectThread("t2");
    public static class ChangeObjectThread extends Thread{
        public ChangeObjectThread(String name){
            super.setName(name);
        }

        @Override
        public void run() {
            synchronized (u){
                System.out.println("in "+getName());
                LockSupport.park();
                if (Thread.interrupted()){
                    System.out.println(getName()+" 被中断了");
                }
            }
            System.out.println(getName()+" 执行结束");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        t1.start();
        Thread.sleep(1000);
        t2.start();
        t1.interrupt();
        LockSupport.unpark(t2);
    }

}

上面我们使用了一个synchronized锁,让这个两个线程只能同步进入临界区,执行结果为:

in t1
t1 被中断了
t1 执行结束
in t2
t2 执行结束

可见park()响应了中断,但未抛出异常,随后执行结束退出临界区,此后t2进入临界区,随后用unpark()运行结束。

  • 3 min read

CONTRIBUTORS


  • 3 min read