详解LockSupport原理、使用场景及面试题

【Java进阶营】Java技术专题-从底层分析LockSupport原理机制 从底层分析LockSupport原理机制 知识点 LockSupport的介绍 LockSupport类是Java6(JSR166-JUC)引入的一个类,提供了基本的线程同步原语。LockSupport实际上是调用了Unsafe类里的函数,归结到Unsafe里,只有两个函数,而仅仅两个简单的接口,就为上层提供了强大的同步原语,先来解析下两个函数是做什么的。 public native void unpark(Thread jthread); public native void park(boo. 阅读详情

1、LockSupport是什么

  • LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
  • LockSupport中的park()和 unpark()的作用分别是阻塞线程和解除阻塞线程。
  • 3种让线程等待和唤醒的方式:

方式1:使用Object中的wait()方法让线程等待,使用object中的notify()方法唤醒线程
方式2:使用JUC包中Condition的await()方法让线程等待,使用signal()方法唤醒线程
方式3:LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程(可以理解为方式1和方式2的加强版)

2、waitNotify和awaitSignal的限制

  • synchronized -> wait->notify实现线程之间的等待唤醒
import java.util.concurrent.locks.LockSupport;

//   synchronized -> wait->notify
//   lock -> await -> signal
public class LockSupportTest {
    private static Object objectLock = new Object();

    public static void main(String[] args) {

       new Thread(()->{
           synchronized (objectLock){
               System.out.println(Thread.currentThread().getName() + "\t" + "coming in ....");

               try {
                   objectLock.wait();
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
               System.out.println(Thread.currentThread().getName() + "\t" + "被唤醒了 ....");
           }
       },"thA").start();

       new Thread(()->{
           synchronized (objectLock){
               System.out.println(Thread.currentThread().getName() + "\t" + "唤醒其他线程 ....");
               objectLock.notify();
           }

       },"thB").start();

    }
}

输出结果:

thA	coming in ....
thB	唤醒其他线程 ....
thA	被唤醒了 ....

如果让thA暂停三秒钟,让thB先获取锁objectLock,notify方法用来唤醒其他线程(实则没有任何线程等待), 再让thA获取锁,wait方法让thA线程等待,而thA不被唤醒,会一直处于等待/阻塞状态,即"thA 被唤醒了 …”一直不会输出。

  • 调用顺序要先wait,在notify才能正常地实现线程之间的通知和唤醒。
    在这里插入图片描述
    还需要注意的是:
  • wait和notify方法必须要在同步块或者方法里面且成对出现使用,否则会抛出java.lang.IllegalMonitorStateException。
    在这里插入图片描述
  • 实现线程的等待和唤醒,Condition接口中的await和signal方法,同前面使用Object类中的wait和notify方法来实现,其效果大致相同。
  • 都必须要先等待(wait/await),再唤醒(notify/signal);等待和唤醒方法必须要在同步块或者方法里面且成对出现使用,否则会抛出java.lang.IllegalMonitorStateException
    private static Condition condition = lock.newCondition();
    private static Object objectLock = new Object();
    public static void main(String[] args) {

        new Thread(() -> {
            // 当前线程睡眠三秒钟,让thB先执行
            // try {
           //      TimeUnit.SECONDS.sleep(3);
           //  } catch (InterruptedException e) {
           //     throw new RuntimeException(e);
           //  }
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t" + "coming in ....");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName() + "\t" + "被唤醒了 ....");
            } catch (RuntimeException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }, "thA").start();

        new Thread(() -> {
            lock.lock();
            try {
                condition.signal();
                System.out.println(Thread.currentThread().getName() + "\t" + "唤醒其他线程 ....");
            } finally {
                lock.unlock();
            }

        }, "thB").start();
    }

使用LockSupport可以解决如上两个问题,也会使代码更为简练。

3、LockSupport原理分析

  • LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒方法。
  • LockSupport分别使用park、unpark实现等待和唤醒,见官网原话:

Basic thread blocking primitives for creating locks and other synchronization classes.
This class associates, with each thread that uses it, a permit (in the sense of the Semaphore class). A call to park will return immediately if the permit is available, consuming it in the process; otherwise it may block. A call to unpark makes the permit available, if it was not already available. (Unlike with Semaphores though, permits do not accumulate. There is at most one.) link

其解读如下:

  • LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
  • LockSupport类使用了Permit(许可证)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),permit只有两个值1和零,默认是零。
  • 许可看成是一种(0和1)信号量(Semaphore),但与Semaphore不同的是,许可的累加上限是1
  • 通过park()和unpark(thread)方法来实现阻塞和唤醒线程的操作,此外,park()+park(Object blocker) 可以用来阻塞当前线程阻塞传入的具体线程

LockSupport 源码摘要如下:

public class LockSupport {
   //  ...
    public static void park() {
        UNSAFE.park(false, 0L);
    }
    //  ...

    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }
    public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    }
 }
  • park和unpark方法都需要调用Unsafe类中native修饰的方法,底层交由C语言去实现
  • permit默认是0,调用park()方法,当前线程th1就会阻塞,直到别的线程th2调用unpark(Thread thread),将当前线程th1的permit设置为1时(表示当前线程获取到许可),th1会被th2唤醒,然后会将permit再次设置为0并返回。
  • 调用unpark(thread)方法后,就会将th1线程的许可permit设置成1(注意多次调用unpark方法,不会累加,pemit值还是1),使得th1线程被唤醒。

4、LockSupport使用案例

 public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            // 当前线程睡眠三秒钟,让thB先执行
            //try {
            //     TimeUnit.SECONDS.sleep(3);
            //} catch (InterruptedException e) {
            //     throw new RuntimeException(e);
            //}
            System.out.println(Thread.currentThread().getName() + "\t" + "coming in ....");
            LockSupport.park();
                /* 如果这里有两个LockSupport.park(),由于permit的值为1,
                上一行已经使用了permit,所以下一行被注释的打开会导致程序处于一直等待       的状态 * */
            //LockSupport.park();
            System.out.println(Thread.currentThread().getName() + "\t" + "被唤醒了 ....");
        }, "thA");

        threadA.start();

        Thread threadB = new Thread(() -> {
            //try {
            //    TimeUnit.SECONDS.sleep(1);
            //} catch (InterruptedException e) {
            //    throw new RuntimeException(e);
            //}
               //如果有两个LockSupport.unpark(t1),由于permit的值最大为1,所以只能给park一个通行证
            //  LockSupport.unpark(threadA);
            LockSupport.unpark(threadA);
            System.out.println(Thread.currentThread().getName() + "\t" + "唤醒其他线程 ....");
        }, "thB");
        threadB.start();
   }

运行如上程序,即使不加锁,也不会出现异常 IllegalMonitorStateException,也不需要关心线程之间等待和唤醒的先后顺序。

5、总结

  • 没有使用LockSupport的等待唤醒通知机制必须synchronized里面执行wait和notify,在lock里面执行await和signal,这上面这两个都必须要持有锁才能干
  • LockSupport:俗称锁中断,LockSupport 解决了 synchronized 和 lock 的痛点
  • LockSupport不用持有锁块,不用加锁,程序性能好,无须注意唤醒和阻塞的先后顺序,不容易导致卡死

形象理解LockSupport:

  • 线程阻塞需要消耗凭证(permit),这个凭证最多只有1个。
  • 当调用park方法时:
    如果有凭证,则会直接消耗掉这个凭证然后正常退出
    如果无凭证,就必须阻塞等待凭证可用
  • 而unpark则相反,它会增加一个凭证,但凭证最多只能有1个,累加无放。

6、LockSupport面试题

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

因为unpark获得了一个凭证,之后再调用park方法,就可以名正言顺的凭证消费,故不会阻塞。

  • 为什么唤醒两次后阻塞两次,但最终结果还会阻塞线程?

因为凭证的数量最多为1(不能累加),连续调用两次 unpark和调用一次 unpark效果一样,只会增加一个凭证;而调用两次park却需要消费两个凭证,证不够,不能放行。

LockSupport原理解析及源码 目录概览LockSupport解析用法:具体使用:原理概述:源码解析:底层原理:park原理流程图:unpark原理流程图:park() 源码:unpark() 源码:Q & A1. unpark是否可以调用多次,以获取多个permit?2. unpark是否一定要在park之后调用?3. park会像wait()一样睡眠释放当前锁吗? LockSupport解析 LockSupport 底层使用Posix线程库pthreads的系统级别锁互斥量mutex和condition,所以它的系统消耗是比 阅读详情

相关推荐

看完这篇 LockSupport 解析,我的面试终于稳了!

LockSupport 是 JDK 并发包(java.util.concurrent.locks)中的一个工具类,提供了一组低级的、以线程为单位LockSupport.park() 让当前线程阻塞(暂停执行)。LockSupport.unpark(Thread t) 唤醒指定线程。它的底层其实是调用 Unsafe 类的 park() 和 unpark() 方法,因此能提供比 Object.wait() 和 Thread.sleep() 更高效、精准的线程控制。官方定义LockSupport 是用来。

孤芳不自赏 787

LockSupport

LockSupport LockSupport简介 LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,官网对于该类的解释如下图所示,LockSupport中的park()和unpark()的作用分别是阻塞线程和解除阻塞线程。 线程等待和唤醒方法 方式一:使用Object中的wait()方法让线程等待, 使用Object中的notify()方法唤醒线程。 代码演示如下: public class LockSupportDemo { static Object objectLock=

weixin_48276298的博客 305

Day470&471.Netty概述&Netty高性能架构设计 -netty

Netty概述 一、原生 NIO 存在的问题 NIO 的类库和 API 繁杂,使用麻烦:需要熟练掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer等。 需要具备其他的额外技能:要熟悉 Java 多线程编程,因为 NIO 编程涉及到 Reactor 模式,你必须对多线程和网络编程非常熟悉,才能编写出高质量的 NIO 程序。 开发工作量和难度都非常大:例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常流的处理等等。 JDK NIO

阿昌爱Java 1570

LockSupport原理分析

一. LockSupport类介绍 LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程。主要是通过park()和unpark(thread)方法来实现阻塞和唤醒线程的操作的。 每个线程都有一个许可(permit),permit只有两个值1和0,默认是0。 当调用unpark(thread)方法,就会将thread线程的许...

weixin_34114823的博客 325

别再用RIDE了!VSCode+RobotFramework插件打造现代化测试开发环境

本文介绍了如何利用VSCode和RobotFramework插件构建现代化的测试开发环境,替代老旧的RIDE工具。详细讲解了环境配置、插件安装、智能代码补全、测试运行与调试等核心功能,帮助开发者提升自动化测试效率。文章还提供了高级技巧、最佳实践和常见问题解决方案,助力团队实现平滑迁移。

weixin_28829629的博客 480

第4章--CANoe library开发 - 诊断功能

因为专栏要做的是汽车ECU自动化测试程序,测试的是ECU的诊断和刷新,因此就需要利用CANoe的接口,开发一些方便使用的诊断报文收发函数。

j187067046的博客 1396

Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)

00_前言闲聊和课程说明 教学视频 暖身面试题 Redis默认端口是多少?- 6379 link Spring官网地址 - https://spring.io 经典计算机图书看过吗? 01_字符串常量Java内部加载-上 Returns a canonical representation for the string object. A pool of strings, initially empty, is maintained privately by the class String. Whe

KISS 3万+

小龙虾们的好伙伴专栏导航

本文系统解析了OpenClaw技术架构,包括Channel层和网关层的设计实现,并与AgentSkills等技术方案进行对比。同时提供了OpenClaw的系列实用指南,涵盖小龙虾培养、客户资源管理、系统自动化巡检以及技术趋势助手构建等应用场景,帮助用户从零成本入门到高效落地应用,实现业务全流程自动化管理。

wend的博客 209

LockSupport:线程阻塞与唤醒的利器

在Java并发编程中,线程的阻塞与唤醒是常见的操作。传统的`synchronized`和`Object.wait()`/`Object.notify()`虽然能够实现线程间的同步,但在某些场景下显得不够灵活。Java 1.5引入了`LockSupport`类,提供了一种更底层、更灵活的线程阻塞与唤醒机制。本文将深入探讨`LockSupport`的使用、原理及其与传统同步机制的区别

专注Java和MySQL领域知识分享 1400

openbmc 支持mctp over pcie(三)(支持作为endpoint)

本文介绍了在Intel BHS平台上支持MCTP over PCIe端点开发的调试方法。开发基于CodeConstruct和AspeedTech-BMC的开源项目,将内核驱动改为模块形式以便调试。内容包括DTS配置、驱动模块设置步骤,以及如何将BMC配置为端点设备。调试过程涉及内核模块加载、MCTPD启动、参数设置等关键命令,并展示了路由表、地址和邻居信息的测试结果。该方案仅为实验性工作,需注意停止其他使用/dev/aspeed-mctp0接口的应用。

wit_yuan的专栏 1553

【异常】OpenClaw 飞书端 OpenClaw: access not configured. Pairing code: [] Ask the bot owner to approve with

摘要: OpenClaw飞书机器人交互中出现的access not configured报错,是因用户或组织未配置访问权限触发的拦截提示。报错包含组织单元ID和配对校验码,需管理员审批开通权限。普通用户需提交完整报错信息给管理员处理;管理员可通过执行标准化命令单次审批,或批量配置组织白名单优化权限管理。建议提前梳理权限范围、及时同步组织架构变更,并定期审计权限列表以确保安全合规。

奶爸的编程之路,也就一周冷个三天 369

提升--08---LockSupport、淘宝面试题

文章目录LockSupport背景:概念;案例解析1:案例解析2:由此可以看出,LockSupport的unpark()方法可以先于LockSupport的park()方法执行。案例解析3:小结:LockSupport中park()和unpark()方法的实现原理 LockSupport 背景: 我们会以几个小程序为案例,展开对LockSupport的讲解,在以前我们要阻塞和唤醒某一个具体的线程有很多限制比如: ​因为wait()方法需要释放锁,所以必须在synchronized中使用,否则会抛出异常I

时光里的博客 472

错误代码:11300001 数据集 [xxx] 配置错误“=”附近有语法错误(原理分析)

错误代码:11300001 数据集 [1_Workshift] 配置错误“=”附近有语法错误。

码农研究僧的博客 914

JUC第四课——LockSupport、三道面试题、源码阅读原则

LockSupport 基本操作 package character04; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; /** * @author laimouren */ public class LockSupport01 { public static void main(String[] args) { Thread t = new Threa

upset_poor的博客 187

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)

文章目录一、前言二、wait/notify的使用1. 代码演示2. 执行结果3. 测试不在代码块执行(`把上面代码注释1给删除`)4. 修改代码5. 总结三、await/signal的使用1. 代码演示2. 执行结果3. 测试不在代码块执行(`把上面代码注释1给删除`)4. 修改代码5. 总结四、LockSupport的park/unpark的使用1. LockSupport介绍2. park源码查看3. unpark源码查看4. 代码演示5. 结果展示6. 修改代码7. 与前两者比的优点8.总结9.白话文

小王博客基地 986

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

多线程与高并发(四)--LockSupport、淘宝面试题与源码阅读方法论

一、LockSupport 1.传统方法的局限性 以前我们要阻塞和唤醒某一个具体的线程有很多限制 1、因为wait()方法需要释放锁,所以必须在synchronized中使用,否则会抛出异常IllegalMonitorStateException 2、notify()方法也必须在synchronized中使用,并且应该指定对象 3、synchronized()、wait()、notify()对象必须一致,一个synchronized()代码块中只能有一个线程调用wait()或notify() 2.L

qq_36741186的博客 207

Java-JUC笔记-3 线程中断机制与LockSupport

线程中断机制:通过 interrupt()、interrupted()、isInterrupted() 实现线程的协作式中断。 LockSupport:提供更灵活的线程阻塞和唤醒机制,无需锁支持。 线程等待唤醒机制:wait()/notify()、Condition、LockSupport 三种方式各有优劣,适用于不同场景。

m0_56020664的博客 790

(四)【Java精选面试题】AQS底层架构设计原理(含答案)

目录1. 谈谈Lock锁底层实现原理2. synchronized与lock锁之间区别3. 谈谈LockSupport的用法4. AQS核心参数有哪些呢5. Lock锁基本实现原理6. Semaphore信号量底层原理7. CountDownLatch底层原理 1. 谈谈Lock锁底层实现原理 底层基于AQS+Cas+LockSupport锁实现 2. synchronized与lock锁之间区别 Lock基于AQS封装的锁,结合 CAS实现,而Lock锁的升级过程需要自己实现; Synchronized

记录各种Bug解决案例及日常学习内容 1846

阻塞线程怎么唤醒?wait/notify、LockSupport与Condition对比

多线程编程中,线程不会永远处于运行状态,有时它会因为等待锁、等待条件满足或等待任务而进入阻塞或等待状态。理解线程阻塞的本质,是掌握并发协作的第一步——Java中既有synchronized引发的BLOCKED,也有wait()、LockSupport.park()造成的WAITING,它们的唤醒机制截然不同。唤醒阻塞线程,经典方案有wait/notify、LockSupport以及Condition,但真正工程中还要考虑虚假唤醒、中断处理、性能开销等问题。尤其是线程池的阻塞队列选择,本质上就是如何高效挂起与

weixin_32308101的博客 291

多线程与高并发(三) ,LockSupport AQS VarHandle ThreadLocal

LockSupport AQS VarHandle ThreadLocal 强软弱虚 四种引用

阿昊的博客 274

并发编程面试题笔记-线程池篇

本文总结了Java并发编程中线程池相关的核心面试题,主要包括: 线程唤醒机制:介绍了interrupt()、LockSupport.unpark()等唤醒方式,分析了不同阻塞状态的区别 线程同步控制:比较了CountDownLatch和CyclicBarrier的应用场景及实现原理 线程池工作原理:详细解析了线程池的任务处理流程、核心/非核心线程区别、任务队列机制等 线程池实战问题:解答了线程池配置参数、任务取消、队列处理顺序等常见问题 线程协作工具:介绍了CountDownLatch和CyclicBarr

pzz521的博客 1011

java并发面试题,java面试总结架构师中间件

Condition接口可以理解为重入锁的伴生对象。它提供了在重入锁的基础上,进行等待和通知的机制。可以使用 newCondition()方法生成一个Condition对象。在AbstractQueuedSynchronizer内部,有一个队列,我们把它叫做同步等待队列。它的作用是保存等待在这个锁上的线程(由于lock()操作引起的等待)。

m0_61331407的博客 962

【大白话说Java面试题 第120题】【并发篇】第20题:多线程如何循环顺序执行?

摘要:多线程循环顺序执行(如A→B→C→A)是并发编程的经典问题,核心在于线程间精确的信号传递与状态同步。文章深入解析两种主流实现方案:1)ReentrantLock + Condition,通过独立条件队列实现精准唤醒,避免虚假唤醒(需用while循环检查条件),推荐生产环境使用;2)synchronized + wait/notifyAll基础方案,需注意notifyAll可能引发“惊群效应”。关键设计要素包括状态标识(volatile保证可见性)、等待/唤醒机制及循环控制,强调从功能正确性(防御虚假唤

Java后端 | AI智能体应用实战派 | 电脑技能行家 440
上一篇: 计算机网络面试突击总结之应用层
下一篇: 从青铜到王者,带你完成Redis分布式锁的实现和优化
咸鱼也有爱
博客等级 码龄7年 133粉丝 47原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值