你知道LockSupport吗

282 阅读2分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程。主要是通过park()unpark(thread) 方法来实现阻塞和唤醒线程的操作的。

原理: 每个线程都有一个许可(permit),permit只有两个值10,默认是0

  1. 当调用unpark(thread)方法,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,permit值还是1)。

  2. 当调用park()方法,如果当前线程的permit1,那么将permit设置为0,并立即返回。如果当前线程的permit0,那么当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时,park方法会被唤醒,然后会将permit再次设置为0,并返回。

注意:因为permit默认是0,所以一开始调用park()方法,线程必定会被阻塞。调用unpark(thread)方法后,会自动唤醒thread线程,即park方法立即返回。

案例:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/17 2:56 下午
 */
public class LockSupportTest {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " start");
            LockSupport.park();
            System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " 被唤醒");
        });
        t1.setName("t1");
        t1.start();

        TimeUnit.SECONDS.sleep(2);
        LockSupport.unpark(t1);
        System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " 执行 LockSupport.unpark() 完毕");
    }
}

返回结果

1629184171289,t1 start
1629184173290,main 执行 LockSupport.unpark() 完毕
1629184174291,t1 被唤醒

LockSupport.park()是否能够响应线程中断?

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/17 2:56 下午
 */
public class LockSupportTest {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " start");
            System.out.println(System.currentTimeMillis() + "," + ",park()之前中断标志:" + Thread.currentThread().isInterrupted());
            LockSupport.park();
            System.out.println(System.currentTimeMillis() + "," + ",park()之后中断标志:" + Thread.currentThread().isInterrupted());
            System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " 被唤醒");
        });
        t1.setName("t1");
        t1.start();

        TimeUnit.SECONDS.sleep(2);
        t1.interrupt();
        System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " 执行 LockSupport.unpark() 完毕");
    }
}

返回结果

1629186355905,t1 start
1629186355905,,park()之前中断标志:false
1629186357905,main 执行 LockSupport.unpark() 完毕
1629186357905,,park()之后中断标志:true
1629186357905,t1 被唤醒

LockSupport.park方法让线程等待之后,唤醒方式有2种

  1. 调用LockSupport.unpark方法
  2. 调用等待线程的 interrupt()方法,给等待的线程发送中断信号,可以唤醒线程