java LockSupport实现原理示例解析

 更新时间:2023年01月09日 09:19:53   作者:小海编码日记  
这篇文章主要为大家介绍了java LockSupport实现原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

前文中了解到AQS借助LockSupport.park和LockSupport.unpark完成线程的阻塞和唤醒,那么LockSupport内部又是怎么实现的?这是一个什么类?

LockSupport是用于使用锁阻塞线程的基础实现,是其他同步类的基础,这个类为每个使用它的线程关联一个许可证(有点类似于Semaphore),如果许可证可用,线程调用park方法时会立即返回,线程正常执行,否则当前线程阻塞,直到有其他线程调用unpark使得许可证可用,此时线程被唤醒,再次尝试获取许可证,其内部定义的park和unpark方法提供了阻塞和解决阻塞的基本实现。

LockSupport常见函数

如下表所示:

函数名称说明备注
void park()阻塞当前线程在下列情况发生时唤醒: 1.调用unpark函数,释放该线程的许可; 2.该线程被中断; 3.设置的阻塞超时时间耗尽; 4.到达设置的指定时间
void park(Object blocker)使用指定的blocker对象阻塞当前线程唤醒条件,park中已说明
void parkNanos(long nanos)阻塞当前线程直到超时时间耗尽,nanos为指定的超时时间唤醒条件,park中已说明
void parkNanos(Object blocker, long nanos)在超时时间耗尽前,使用指定的blocker对象阻塞当前线程,如果在到达超时时间后,许可仍不可用,则结束阻塞唤醒条件,park中已说明
void parkUntil(long deadline)在指定时间前,阻塞该线程,如果在到达指定时间后,许可仍不可用,则结束阻塞唤醒条件,park中已说明
void parkUntil(Object blocker, long deadline)在指定时间前,使用指定的对象阻塞该线程,如果在到达指定时间后,许可仍不可用,则结束阻塞唤醒条件,park中已说明
void unpark(Thread thread)用于唤醒传入的在阻塞中的线程/
Object getBlocker(Thread t)获取当前线程的阻塞对象/
void setBlocker(Thread t, Object arg)使用指定对象为线程设置阻塞对象/

LockSupport.park

ReentrantLock中调用LockSupport.park代码如下所示:

 // AbstractQueuedSynchronizer.java
 private final boolean parkAndCheckInterrupt() {
     LockSupport.park(this);
     return Thread.interrupted();
 }

在LockSupport中,void park(Object blocker)实现代码如下:

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

可以看到在park流程中主要包含以下过程:

获取当前线程

将传入的对象设置为该线程的parkBlocker

setBlocker函数实现如下所示:

 private static void setBlocker(Thread t, Object arg) {
     // Even though volatile, hotspot doesn't need a write barrier here.
     UNSAFE.putObject(t, parkBlockerOffset, arg);
 }

可以看到这里新出现了UNSAFE和parkBlockerOffset两个标识,这两个是用来干嘛的?我们一起看看其声明的代码:

 private static final sun.misc.Unsafe UNSAFE;
 private static final long parkBlockerOffset;
 static {
     try {
         UNSAFE = sun.misc.Unsafe.getUnsafe();
         Class<?> tk = Thread.class;
         parkBlockerOffset = UNSAFE.objectFieldOffset
             (tk.getDeclaredField("parkBlocker"));
         .....
     } catch (Exception ex) { throw new Error(ex); }
 }

可以看到UNSAFE对象是通过Unsafe.getUnsafe()获取的,那么Unsafe这个类到底是干嘛的?

大家都知道Java对象在内存中创建,大多数情况下我们都是通过类的对象去修改和访问内存中的数据的,那么如果需要直接从内存修改某一对象的取值,应该怎么做呢?就是使用Unsafe类,该类只允许在JDK信任的类中调用(当前也可以用反射实例化该类对象)。

在Unsafe类中定义了两个重要函数park和unpark,其中park用于实现线程阻塞,unpark用于实现线程唤醒(Unsafe本质上是操作线程的Parker对象来完成线程阻塞和唤醒的,具体见参考链接,了解即可),上文中的parkBlockerOffset正是定义了Thread类的parkBlocker属性成员的内存偏移量,使用该值再结合Unsafe对象就可以实现直接操作内存中的parkBlocker值的目的,Thread类中的parkBlocker声明如下:

 // Thread.java
 volatile Object parkBlocker;

可以得到这一环节主要是将AQS作为blocker设置到当前线程的parkBlocker成员属性上。

CAS底层也是通过Unsafe执行的

执行UNSAFE.park

结合上文可知,这步完成后,当前线程阻塞

设置线程的parkBlocker为null

第三步中线程处于阻塞状态,当然就不能执行设置parkBlocker为null的操作了,那么什么时候执行呢?当线程从阻塞状态唤醒时,执行该步骤,使得线程的parkBlocker对象恢复初始状态。

LockSupport.unpark

LockSupport.unpark代码如下所示:

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

可以看出当传入的线程不为空时,执行Unsafe的park函数唤醒当前线程,取消阻塞,此时继续执行park函数中的setBlocker(null),将parkBlocker成员设置为null。

参考链接  https://www.jb51.net/article/272073.htm

以上就是java LockSupport实现原理示例解析的详细内容,更多关于java LockSupport原理的资料请关注脚本之家其它相关文章!

相关文章

  • MyBatis注解实现动态SQL问题

    MyBatis注解实现动态SQL问题

    这篇文章主要介绍了MyBatis注解实现动态SQL问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • SpringBoot使用spring.config.import多种方式导入配置文件

    SpringBoot使用spring.config.import多种方式导入配置文件

    本文主要介绍了SpringBoot使用spring.config.import多种方式导入配置文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Maven配置文件修改及导入第三方jar包的实现

    Maven配置文件修改及导入第三方jar包的实现

    本文主要介绍了Maven配置文件修改及导入第三方jar包的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • Springboot项目异常处理及返回结果统一

    Springboot项目异常处理及返回结果统一

    这篇文章主要介绍了Springboot项目异常处理及返回结果统一,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-08-08
  • Java编程使用卡片布局管理器示例【基于swing组件】

    Java编程使用卡片布局管理器示例【基于swing组件】

    这篇文章主要介绍了Java编程使用卡片布局管理器,结合实例形式分析了java基于swing组件的卡片布局管理器具体实现与使用技巧,需要的朋友可以参考下
    2018-01-01
  • Java中Thread类基本用法详解

    Java中Thread类基本用法详解

    Java中的Thread类是用于创建和管理线程的类,Thread类提供了许多方法来管理线程,包括启动线程、中断线程、暂停线程等,下面这篇文章主要给大家介绍了关于Java中Thread类基本用法的相关资料,需要的朋友可以参考下
    2023-06-06
  • Maven发布Jar包中文乱码解决方法

    Maven发布Jar包中文乱码解决方法

    这篇文章主要介绍了Maven发布Jar包中文乱码解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Java实现读取设置pdf属性信息

    Java实现读取设置pdf属性信息

    这篇文章主要为大家详细介绍了如何使用Java实现读取设置pdf属性信息,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-01-01
  • Java中get/post的https请求忽略ssl证书认证浅析

    Java中get/post的https请求忽略ssl证书认证浅析

    因为Java在安装的时候,会默认导入某些根证书,所以有些网站不导入证书,也可以使用Java进行访问,这篇文章主要给大家介绍了关于Java中get/post的https请求忽略ssl证书认证的相关资料,需要的朋友可以参考下
    2024-01-01
  • 基于Java实现简单的时序数据压缩算法

    基于Java实现简单的时序数据压缩算法

    这篇文章主要为大家详细介绍了如何利用Java语言实现简单易懂的时序数据压缩算法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2022-06-06

最新评论