文章目录

  • 前言
  • 一、LockSupport是什么?
  • 二、Object中wait和Notify限制
    • 1.代码模拟
  • 三、Condition接口中的await后signal使用限制
    • 1.代码模拟
    • 2.存在问题
  • 四、LockSupport方法介绍
    • 1.传统的synchronized和Lock实现等待唤醒通知的约束
    • 2. LockSupport类中的park等待和unpark唤醒
    • 3.代码模拟
    • 4.重点说明
    • 5.形象的理解
    • 6.面试题

前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、LockSupport是什么?

  1. LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。

  2. LockSupport中的park()和 unpark()的作用分别是阻塞线程和解除阻塞线程。

  3. 总之,比wait/notify,await/signal更强。

3种让线程等待和唤醒的方法

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

二、Object中wait和Notify限制

1.代码模拟

public class WaitNotifyDemo {static Object lock = new Object();public static void main(String[] args) {new Thread(()->{synchronized (lock) {System.out.println(Thread.currentThread().getName()+" come in.");try {lock.wait();} catch (Exception e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName()+" 换醒.");}, "Thread A").start();new Thread(()->{synchronized (lock) {lock.notify();System.out.println(Thread.currentThread().getName()+" 通知.");}}, "Thread B").start();}
}

三、Condition接口中的await后signal使用限制

1.代码模拟

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class ConditionAwaitSignalDemo {public static void main(String[] args) {ReentrantLock lock = new ReentrantLock();Condition condition = lock.newCondition();new Thread(()->{try {System.out.println(Thread.currentThread().getName()+" come in.");lock.lock();condition.await();              } catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}System.out.println(Thread.currentThread().getName()+" 换醒.");},"Thread A").start();new Thread(()->{try {lock.lock();condition.signal();System.out.println(Thread.currentThread().getName()+" 通知.");}finally {lock.unlock();}},"Thread B").start();}}

测试结果

Thread A come in.
Thread B 通知.
Thread A 换醒.

2.存在问题

  1. await和signal方法必须要在同步块或者方法里面且成对出现使用,否则会抛出java.lang.IllegalMonitorStateException。

  2. 调用顺序要先await后signal才OK。

四、LockSupport方法介绍

1.传统的synchronized和Lock实现等待唤醒通知的约束

  1. 线程先要获得并持有锁,必须在锁块(synchronized或lock)中
  2. 必须要先等待后唤醒,线程才能够被唤醒

2. LockSupport类中的park等待和unpark唤醒

LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。

LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),permit只有两个值1和零,默认是零。

可以把许可看成是一种(0.1)信号量(Semaphore),但与Semaphore不同的是,许可的累加上限是1。

通过park()和unpark(thread)方法来实现阻塞和唤醒线程的操作

park()/park(Object blocker) - 阻塞当前线程阻塞传入的具体线程

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);}...
}

permit默认是0,所以一开始调用park()方法,当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时,park方法会被唤醒,然后会将permit再次设置为0并返回。

unpark(Thread thread) - 唤醒处于阻塞状态的指定线程

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

调用unpark(thread)方法后,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,pemit值还是1)会自动唤醒thead线程,即之前阻塞中的LockSupport.park()方法会立即返回。

3.代码模拟

public class LockSupportDemo {public static void main(String[] args) {Thread a = new Thread(()->{
//          try {
//              TimeUnit.SECONDS.sleep(2);
//          } catch (InterruptedException e) {
//              e.printStackTrace();
//          }System.out.println(Thread.currentThread().getName() + " come in. " + System.currentTimeMillis());LockSupport.park();System.out.println(Thread.currentThread().getName() + " 换醒. " + System.currentTimeMillis());}, "Thread A");a.start();Thread b = new Thread(()->{try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}LockSupport.unpark(a);System.out.println(Thread.currentThread().getName()+" 通知.");}, "Thread B");b.start();}}

测试结果

Thread A come in.
Thread B 通知.
Thread A 换醒.

正常 + 无锁块要求。

先前错误的先唤醒后等待顺序,LockSupport可无视这顺序。

4.重点说明

  1. LockSupport是用来创建锁和共他同步类的基本线程阻塞原语。

  2. LockSuport是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻寨之后也有对应的唤醒方法。归根结底,LockSupport调用的Unsafe中的native代码。

  3. LockSupport提供park()和unpark()方法实现阻塞线程和解除线程阻塞的过程

  4. LockSupport和每个使用它的线程都有一个许可(permit)关联。permit相当于1,0的开关,默认是0,调用一次unpark就加1变成1,调用一次park会消费permit,也就是将1变成0,同时park立即返回。

  5. 如再次调用park会变成阻塞(因为permit为零了会阻塞在这里,一直到permit变为1),这时调用unpark会把permit置为1。每个线程都有一个相关的permit, permit最多只有一个,重复调用unpark也不会积累凭证。

5.形象的理解

  1. 线程阻塞需要消耗凭证(permit),这个凭证最多只有1个。

  2. 当调用park方法时
    如果有凭证,则会直接消耗掉这个凭证然后正常退出。
    如果无凭证,就必须阻塞等待凭证可用。

  3. 而unpark则相反,它会增加一个凭证,但凭证最多只能有1个,累加无放。

6.面试题

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

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

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

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

Java之LockSupport详解相关推荐

  1. 5W字高质量java并发系列详解教程(上)-附PDF下载

    文章目录 第一章 java.util.concurrent简介 主要的组件 Executor ExecutorService ScheduledExecutorService Future Count ...

  2. Java内存溢出详解之Tomcat配置

    Java内存溢出详解 转自:http://elf8848.iteye.com/blog/378805 一.常见的Java内存溢出有以下三种: 1. java.lang.OutOfMemoryError ...

  3. java基础(十三)-----详解内部类——Java高级开发必须懂的

    java基础(十三)-----详解内部类--Java高级开发必须懂的 目录 为什么要使用内部类 内部类基础 静态内部类 成员内部类 成员内部类的对象创建 继承成员内部类 局部内部类 推荐博客 匿名内部 ...

  4. Java类加载机制详解【java面试题】

    Java类加载机制详解[java面试题] (1)问题分析: Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数 ...

  5. Java线程池详解学习:ThreadPoolExecutor

    Java线程池详解学习:ThreadPoolExecutor Java的源码下载参考这篇文章:Java源码下载和阅读(JDK1.8) - zhangpeterx的博客 在源码的目录java/util/ ...

  6. Java 线程池详解学习:FixedThreadPool,CachedThreadPool,ScheduledThreadPool...

    Java常用的线程池有FixedThreadPool和CachedThreadPool,我们可以通过查看他们的源码来进行学习. Java的源码下载参考这篇文章:Java源码下载和阅读(JDK1.8) ...

  7. 关于Java的Classpath详解

    关于Java的Classpath详解 Java 的新入门者对classpath往往比较困惑,为何在开发环境中能运行的东东出去就不好,或在外面运行的东东挺溜的进了开发环境就死菜. java的优点就是他是 ...

  8. java异常体系结构详解

    java异常体系结构详解 参考文章: (1)java异常体系结构详解 (2)https://www.cnblogs.com/hainange/p/6334042.html 备忘一下.

  9. java异常处理机制详解

    java异常处理机制详解 参考文章: (1)java异常处理机制详解 (2)https://www.cnblogs.com/vaejava/articles/6668809.html 备忘一下.

最新文章

  1. Android Nand Flash 分区
  2. boost::safe_numerics::base_type相关的测试程序
  3. 程序员建议(忘记从哪里转的了,反正是csdn上的一个兄弟)
  4. Spring5的通信报文
  5. 按15分钟取数据_【数量技术宅|金融数据分析系列分享】套利策略的价差序列计算,恐怕没有你想的那么简单...
  6. echarts 地图自定义图标_DMKB08:Echarts 分段设色
  7. Java集合之Hashtable源码分析
  8. wince模拟器访问网络_在Wince模拟器接入网络的方法
  9. python安装第三方扩展包_【Python】pip - 安装第三方包的神器
  10. Python使用修饰器强制函数只接收关键参数
  11. 伪静态设置php,php伪静态设置
  12. 2022年P气瓶充装最新解析及P气瓶充装新版试题
  13. 我国高分系列卫星遥感影像介绍
  14. 见过世面的程序员,到底有多厉害
  15. 用python暴力破解压缩包密码
  16. 直播 | 2017阿里双11在线技术峰会
  17. 深入讨论Python中的序列切片语法
  18. 在HTML中添加视频的代码
  19. 工具收集 - 搜索工具
  20. Apollo Cyber RT学习手册(基于Ubuntu18.04、Apollo 6.0_edu)

热门文章

  1. 编辑视频贴纸软件_视频特效编辑软件下载-视频特效编辑器下载V10.9.93-西西软件下载...
  2. python 发送邮件不显示附件_求助:写python脚本发 带有附件的邮件, 收到邮件后,发现附件直接显示在屏幕上了,而不是以附件形式...
  3. matlab找距离最近的元素,如何用MATLAB找到给定坐标的最近点?
  4. thinkphp框架学习笔记(1)
  5. 黑科技!两行代码完美解决:同时设置overflow-x:hidden,overflow-y:visible无效的问题...
  6. Maven--部署构件至 Nexus
  7. SQLLite数据库操作
  8. C# 基础知识和VS2010的小技巧总汇(2)[转]
  9. wangeditor php上传本地图片,wangEditor 本地上传图片配置
  10. Docker Compose如何与SkyEye完美结合