Java LockSupport常用方法的源码分析

 更新时间:2023年02月20日 14:04:37   作者:小威要向诸佬学习呀  
这篇文章主要为大家详细介绍了Java LockSupport类中的方法和部分源码,以及面试常问到的一个小问题,感兴趣的小伙伴可以跟随小编一起学习一下

LockSupport类常用方法源码

LockSupport只是一个简单的基础类,位于java.util.concurrent.locks包下,多用于线程的阻塞和唤醒,因此LockSupport也被称为其他线程的工具类。

LockSupport类的源码有标注,LockSupport类无法实例化。LockSupport类的底层是有Unsafe类实现的,LockSupport加载时的初始化也用到了Unsafe获取成员的偏移量,其源码如下:

    // Hotspot implementation via intrinsics API
    private static final sun.misc.Unsafe UNSAFE;
    private static final long parkBlockerOffset;
    private static final long SEED;
    private static final long PROBE;
    private static final long SECONDARY;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> tk = Thread.class;
            parkBlockerOffset = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("parkBlocker"));
            SEED = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSeed"));
            PROBE = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomProbe"));
            SECONDARY = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
        } catch (Exception ex) { throw new Error(ex); }
    }

LockSupport类中有一些核心的线程操作方法,多用于线程的阻塞与唤醒。

调用park()方法使线程阻塞:

    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }
    private static void setBlocker(Thread t, Object arg) {
        // Even though volatile, hotspot doesn't need a write barrier here.
        UNSAFE.putObject(t, parkBlockerOffset, arg);
    }

调用park(Object blocker)对传入的线程进行阻塞

    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }

在截止时间之前阻塞传入的某个线程:

    public static void parkUntil(Object blocker, long deadline) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(true, deadline);
        setBlocker(t, null);
    }

在nanos的时间范围内阻塞传入的线程:

    public static void parkNanos(Object blocker, long nanos) {
        if (nanos > 0) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            UNSAFE.park(false, nanos);
            setBlocker(t, null);
        }
    }

唤醒传入的线程:

    public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    }

wait/notify方法和park/unpark方法区别

LockSupport类中的方法还有很多,在此先列举到这里。当我们看到阻塞和唤醒方法时,我们会联想到另一组唤醒方法wait()和notify(),这两组方法还是有所区别的。

这里直接记录下结论:wait和notify方法只能在同步代码块中使用(即必须与synchronized连用);必须先执行wait方法,然后再执行notify方法唤醒线程,调换顺序的话线程仍处于阻塞状态。

而park()和unpark()方法与之不同,这里可以通过代码运行结果来看:

package XIAOWEI;
import java.util.concurrent.locks.LockSupport;

​​​​​​​public class Xiaowei{
    public static void main(String[] args) {
        Thread A = new Thread(()-> {
            System.out.println("线程A已经被阻塞QWQ");
            LockSupport.park();
            System.out.println("线程A被线程B唤醒啦~~~");
        });
        A.start();
        new Thread(()->{
            System.out.println("线程B在唤醒线程A ing~~~");
            LockSupport.unpark(A);
        },"B").start();
    }
}

那如果我们先通过线程B唤醒线程A,然后再让线程A阻塞呢(让线程A的阻塞休眠两秒)?

package XIAOWEI;
import java.util.concurrent.locks.LockSupport;
public class Xiaowei {
    public static void main(String[] args) {
        Thread A = new Thread(()-> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程A已经被阻塞QWQ(第二版)");
            LockSupport.park();
            System.out.println("线程A被线程B唤醒啦~~~(第二版)");
        });
        A.start();
        new Thread(()->{
            System.out.println("线程B在唤醒线程A ing~~~驾驾驾");
            LockSupport.unpark(A);
        },"B").start();
    }
}

由上面输出结果来看,虽然线程B先唤醒了线程A,然后线程A再开始阻塞,但是线程A还是处于唤醒状态,这是为什么呢?

接下来我找了段LockSupport类中的注释,其实有时看看注释也挺有意思的哈哈:

 * <p>This class associates, with each thread that uses it, a permit
 * (in the sense of the {@link java.util.concurrent.Semaphore
 * Semaphore} class). A call to {@code park} will return immediately
 * if the permit is available, consuming it in the process; otherwise
 * it <em>may</em> block.  A call to {@code unpark} makes the permit
 * available, if it was not already available. (Unlike with Semaphores
 * though, permits do not accumulate. There is at most one.)

这段话大意是说,LockSupport类使用permits这个东西来实现线程的阻塞和唤醒。每一个线程都会使用到(拥有)permit,且permit的值默认为0。接着它又说,这个概念和Semaphore信号量差不多,但是permit的值只有0和1两个值。哦~原来是这样。

对于上面例子,线程B调用unpark方法唤醒A后,会使得线程A的permit值为1,当线程调用park方法使自己阻塞时,发现自己已经有许可(permit)了,就会继续向下执行业务,而不会阻塞不动。

到此这篇关于Java LockSupport常用方法的源码分析的文章就介绍到这了,更多相关Java LockSupport内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Idea进行pull的时候Your local changes would be overwritten by merge.

    Idea进行pull的时候Your local changes would be

    这篇文章主要介绍了Idea进行pull的时候Your local changes would be overwritten by merge.具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • 堆排序算法的讲解及Java版实现

    堆排序算法的讲解及Java版实现

    这篇文章主要介绍了堆排序算法的讲解及Java版实现,堆排序基于堆这种数据结构,在本文中对堆的概念也有补充介绍,需要的朋友可以参考下
    2016-05-05
  • 详解Java的类加载机制及热部署的原理

    详解Java的类加载机制及热部署的原理

    今天我要讲的就是Java的热部署的原理,由于热部署的原理和类的加载机制有关,所以打算讲一下类加载的机制,文中介绍的非常详细,需要的朋友可以参考下
    2021-05-05
  • Spring Boot Admin实现服务健康预警功能

    Spring Boot Admin实现服务健康预警功能

    这篇文章主要介绍了Spring Boot Admin实现服务健康预警功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • IDEA中使用Typora编辑md文件的方法

    IDEA中使用Typora编辑md文件的方法

    这篇文章主要介绍了IDEA中使用Typora编辑md文件的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • mybatis update set 多个字段实例

    mybatis update set 多个字段实例

    这篇文章主要介绍了mybatis update set 多个字段实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • Java执行hadoop的基本操作实例代码

    Java执行hadoop的基本操作实例代码

    这篇文章主要介绍了Java执行hadoop的基本操作实例代码的相关资料,需要的朋友可以参考下
    2017-04-04
  • Spring Boot2开发之Spring Boot整合Shiro两种详细方法

    Spring Boot2开发之Spring Boot整合Shiro两种详细方法

    这篇文章主要介绍了Spring Boot2开发之Spring Boot整合Shiro详细方法,需要的朋友可以参考下
    2020-03-03
  • Spring Boot线程池使用的一些实用心得

    Spring Boot线程池使用的一些实用心得

    理论上线程越多程序可能更快,但在实际使用中我们需要考虑到线程本身的创建以及销毁的资源消耗,以及保护操作系统本身的目的我们通常需要将线程限制在一定的范围之类,这篇文章主要给大家介绍了关于Spring Boot线程池使用的一些实用心得,需要的朋友可以参考下
    2021-09-09
  • SPRINGBOOT读取PROPERTIES配置文件数据过程详解

    SPRINGBOOT读取PROPERTIES配置文件数据过程详解

    这篇文章主要介绍了SPRINGBOOT读取PROPERTIES配置文件数据过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12

最新评论