天天看点

并发编程--LockSupport工具类介绍、线程等待和唤醒的方式对比及使用示例1. 介绍2. 代码示例参考

1. 介绍

1.1. LockSupport类介绍

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

每个线程都有一个许可(permit),permit只有两个值1和0,默认是0。

  • 当调用unpark(thread)方法,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,permit值还是1)。
  • 当调用park()方法,如果当前线程的permit是1,那么将permit设置为0,并立即返回。如果当前线程的permit是0,那么当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时,park方法会被唤醒,然后会将permit再次设置为0,并返回。如果调用unpark方法或者当前线程被中断,从能从park()方法中返回

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

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

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

1.2. 线程等待和唤醒方式

  1. Object中的wait、notify、notifyAll方法
  2. juc中Condition接口提供的await、signal、signalAll方法
  3. juc中的LockSupport提供的park、unpark方法

关于Object和Condtion中线程等待和唤醒的局限性是:线程需要先获取锁;唤醒方法需要在等待方法之后调用,线程才能够被唤醒

1.3. 线程等待和唤醒方式对比

对比点 Object Condtion LockSupport
前置条件 需要在synchronized中运行 需要先获取Lock的锁
无限等待 支持 支持 支持
超时等待 支持 支持 支持
等待到将来某个时间返回 不支持 支持 支持
等待状态中释放锁 会释放 会释放 不会释放
唤醒方法先于等待方法执行,能否唤醒线程 可以
是否能响应线程中断
线程中断是否会清除中断标志
是否支持等待状态中不响应中断 不支持 支持 不支持

2. 代码示例

LockSupport.park(new BlockerDemo());此方法的参数blocker主要是排查问题使用的。这个参数会在线程堆栈信息中打印出来,方便排查问题,其他暂无他用

import lombok.extern.slf4j.Slf4j;

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

@Slf4j
public class LockSupportTest {
    static class BlockerDemo {
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.info(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " start!");
            LockSupport.park();
            log.info(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " 被唤醒!");
        },"线程1");
        t1.start();

        Thread t2 = new Thread(() -> {
            log.info(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " start!");
            LockSupport.park(new BlockerDemo());
            log.info(System.currentTimeMillis() + "," + Thread.currentThread().getName() + " 被唤醒!");
        },"线程2");
        t2.start();

        TimeUnit.SECONDS.sleep(5);
        LockSupport.unpark(t1);
        LockSupport.unpark(t2);
    }
}
           

参考

https://cloud.tencent.com/developer/article/1551323