java并发编程-LockSupport

java / 2022-08-22
0 1,408

LockSupport

package com.fzkj.juc.locksupport;

import java.util.concurrent.locks.LockSupport;

/**
 * @DESCRIPTION
 */
public class LockSupportDemo {

    /**
     * LockSupport 采用发放凭证的方式来阻塞线程(凭证最多为1),park方法一次会消耗掉1个凭证,unpark一次发放一个凭证(最多为1)。
     * 当凭证为0的时候,线程会阻塞,直到有凭证。
     * @param args
     */

    public static void main(String[] args) {
        DoubleUnparkAndPark();
    }

    // 两次阻塞、两次唤醒
    private static void DoubleUnparkAndPark() {
        Thread a = new Thread(() -> {
            System.out.println("------ 进入a线程 ------");
            LockSupport.park(); // 阻塞 和之前的 wait方法作用类似
            LockSupport.park(); // 阻塞 和之前的 wait方法作用类似
            System.out.println("------ a线程被唤醒 ------");
        });
        a.start();
        Thread b = new Thread(() -> {
            LockSupport.unpark(a);
            LockSupport.unpark(a);
            System.out.println("------ 唤醒线程 ------");
        });
        b.start();
    }

    // 先唤醒 再 阻塞
    private static void UnparkBeforePark() {
        Thread a = new Thread(() -> {
            System.out.println("------ 进入a线程 ------");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            LockSupport.park(); // 阻塞 和之前的 wait方法作用类似
            System.out.println("------ a线程被唤醒 ------");
        });
        a.start();
        Thread b = new Thread(() -> {
            LockSupport.unpark(a);
            System.out.println("------ 唤醒线程 ------");
        });
        b.start();
    }

    // 常规多线程流程:阻塞 -> 唤醒
    private static void LockSupportSimple() {
        Thread a = new Thread(() -> {
            System.out.println("------ 进入a线程 ------");
            LockSupport.park(); // 阻塞 和之前的 wait方法作用类似
            System.out.println("------ a线程被唤醒 ------");
        });
        a.start();
        Thread b = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            LockSupport.unpark(a);
            System.out.println("------ 唤醒线程 ------");
        });
        b.start();
    }
}

由于基于凭证的方式来达到线程阻塞的目的。LockSupport并不需要在同步代码块中才能用(wait/notify、await/signal需要在同步代码块中才能使用,而且阻塞和唤醒的顺序不能反,否则会死锁)。

相关面试题

为什么可以先唤醒线程,后阻塞线程?

LockSupport之所以会阻塞线程,就是因为park方法会等待一个凭证,默认值是0,代表没有凭证,而 unpark方法会发放一个凭证,之后调用park方法的时候直接消耗凭证,就不会阻塞。

为什么唤醒两次再阻塞两次,最终结果还是会阻塞?(两次unpark、两次park)

因为凭证最多只能是1。两次unpark后的凭证还是1,而两次park中第一次正常,第二次由于没有凭证就会阻塞。