文章目录

  • 前言
  • 一、看看JDK的代码注释
  • 二、案例
    • 1. 查看线程状态
    • 2.线程被打断,不抛异常
    • 2.是否会释放锁
    • 3.传递自定义数据
  • 总结

前言

Java的线程休眠我们从Thread.sleep到Object.wait(),都进行了逐一讲解,现在我们研究最后一种方式LockSupport.park()。


一、看看JDK的代码注释

 /*** Disables the current thread for thread scheduling purposes unless the* permit is available.翻译:除非许可证可用,否则禁用当前出于线程调度目的线程。* <p>If the permit is available then it is consumed and the call* returns immediately; otherwise the current thread becomes disabled* for thread scheduling purposes and lies dormant until one of three* things happens:翻译:如果许可是可用的,那么这个许可会被消费掉,并且方法立刻返回。否则的话,当前的线程会被变成不可以用,并处于休眠状态,直至下面三种情况发生:* <ul>** <li>Some other thread invokes {@link #unpark unpark} with the* current thread as the target; or翻译:其他线程调用了unpark(Thread t) 方法,参数t就是被休眠park的线程* <li>Some other thread {@linkplain Thread#interrupt interrupts}* the current thread; or*翻译:其他线程interrupts了此线程* <li>The call spuriously (that is, for no reason) returns.* </ul>*翻译:调用方法莫名其妙的返回了(没有什么原因)* <p>This method does <em>not</em> report which of these caused the* method to return. Callers should re-check the conditions which caused* the thread to park in the first place. Callers may also determine,* for example, the interrupt status of the thread upon return.* * 翻译:该方法不会报道是由于哪一种情况导致的返回。* 调用者应该自行检查原因,调用者也可能根据返回的线程状态,进行推断。* */public static void park() {UNSAFE.park(false, 0L);}

从上面的注释我们可以看出来和之前的Thread.sleep、Object.wait()不同的是,该方法不会直接进入休眠,而是会先根据一个permit来进行判断,如果有了permit,那么方法直接返回,如果没有得到permit才会进入休眠状态。
那么进入休眠状态后,有三种情况会被打破
1、其他线程调用了unpark()方法,将该线程unpark了。
2、其他线程interrupts了该线程
3、其他莫名其妙的原因导致的
最后,就是方法不会告知调用方具体是哪一种原因导致了解除睡眠状态,调用者应该重新检查线程,在第一次被park的条件。调用者也可以根据返回,来判断线程的中断状态。

另外,我们也可以看出来,此方法不会抛出受检查异常,这一点和Thread.sleep、Object.wait()不同。

二、案例

1. 查看线程状态

代码如下:

package com.kinyang.lockSupport;import java.util.concurrent.locks.LockSupport;/*** @author KinYang.Liu* @date 2021/6/15 9:46 上午*/
public class LockSupportTest {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{LockSupport.parkNanos(3000*4000*1000L);});Thread t2 = new Thread(()->{LockSupport.park();});t1.start();t2.start();Thread.sleep(1000L);System.out.println("查看一下 t1 线程执行parkNanos的状态:"+t1.getState());System.out.println("查看一下 t2 线程执行park的状态:"+t2.getState());}
}

运行结果

从结果我们可以看出来:LockSupport.park()方法会进入WAITING状态,而LockSupport.parkNanos(long nanos) 会进入TIMED_WAITING状态,这一点和Object.wait是一致的。
可以指定一个休眠时间,不指定就是永久休眠,不会自动唤醒。

2.线程被打断,不抛异常

代码如下:

package com.kinyang.lockSupport;import java.util.concurrent.locks.LockSupport;/*** @author KinYang.Liu* @date 2021/6/15 9:46 上午*/
public class LockSupportTest2 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{System.out.println("t1 线程开始执行");System.out.println("t1 线程 park()  ");LockSupport.park();System.out.println("t1 线程 继续执行");System.out.println("t1 线程 当前的 Interrupt 状态:"+Thread.currentThread().isInterrupted());});t1.start();Thread.sleep(1000L);//  unpark t1线程LockSupport.unpark(t1);}
}

执行结果

当通过LockSupport.unpark()唤醒线程的时候,线程的Interrupt 状态是fasle

package com.kinyang.lockSupport;import java.util.concurrent.locks.LockSupport;/*** @author KinYang.Liu* @date 2021/6/15 9:46 上午*/
public class LockSupportTest2 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{System.out.println("t1 线程开始执行");System.out.println("t1 线程 park()  ");LockSupport.park();System.out.println("t1 线程 继续执行");System.out.println("t1 线程 当前的 Interrupt 状态:"+Thread.currentThread().isInterrupted());});t1.start();Thread.sleep(1000L);/// 将t1 线程打断t1.interrupt();}
}

运行结果

当我们通过 interrupt打断线程的时候,线程的Interrupt 状态是true。

通过上面两个例子,我们可以看到LockSupport.park();不会抛出受检查异常,当出现被打断的情况下,也不会抛出异常,但是会将Interrupt的状态修改,也就是当我们的线程被唤醒后,我们可以通过Interrupt的状态来判断,我们的线程是不是被interrupt的还是被unpark或者到达指定休眠时间。
这一点和Thread.sleep和Object.wait()不同,他们两个当线程被打断的时候,会抛出异常,在catch到异常的时候,interrupt的状态其实是没有的,也就是你在catch代码块中得到的interrupt状态永远是false。

2.是否会释放锁

代码如下:

package com.kinyang.lockSupport;import java.util.Scanner;
import java.util.concurrent.locks.LockSupport;/*** @author KinYang.Liu* @date 2021/6/15 9:46 上午*/
public class LockSupportTest3 {private static Object monitor = new Object();public static void main(String[] args) throws InterruptedException { 创建一个 t1 线程Thread t1 = new Thread(() -> {System.out.println("t1 尝试获取锁");synchronized (monitor){System.out.println("t1 获取到锁");System.out.println("t1 执行 LockSupport.parkNanos() 方法,休眠该线程!");/// 我们执行 parkNanos 操作,让线程进入休眠,看看其他线程是否能抢到 monitor 锁,///  如果其他线程可以获取到 monitor 锁后,那么说明sleep会释放monitor锁///  否则,说明parkNanos不会释放monitor锁LockSupport.parkNanos(1000*1000*1000*5L);System.out.println("t1 线程执行完成");}},"t1-thread"); 启动t1线程t1.start();/// 这里让主线程休眠1s后,确保t1线程已经执行,并获取到锁Thread.sleep(1000L);Thread t2 = new Thread(() -> {System.out.println("t2 尝试获取锁");synchronized (monitor){System.out.println("t2 获取到锁");System.out.println("执行 t2 方法");}},"t2-thread");t2.start();Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()) {if (scanner.nextLine().equalsIgnoreCase("bye")){System.out.println("再见");break;}else {System.out.println("指令错误");}}}
}

运行结果

从执行结果我们就能看出来是,LockSupport.parkNanos()是不会释放锁的。
其实也很容易理解,LockSupport.park跟synchronized就没有关系,休眠线程的原理和Object.wait不同,LockSupport.park休眠线程不需要依赖monitor锁,所以也就不会涉及到释放与不释放锁,这一点和Thread.sleep()是一致的。

3.传递自定义数据

代码如下:

package com.kinyang.lockSupport;import java.util.HashMap;
import java.util.concurrent.locks.LockSupport;/*** @author KinYang.Liu* @date 2021/6/15 9:46 上午*/
public class LockSupportTest4 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{System.out.println("t1 线程开始执行");System.out.println("t1 线程 parkNanos()  ");HashMap blocker = new HashMap();blocker.put("reason","测试LockSupport的park的blocker");blocker.put("code","1000");LockSupport.parkNanos(blocker,2000*1000*2000L);System.out.println("t1 线程 继续执行");System.out.println("t1 线程 当前的 Interrupt 状态:"+Thread.currentThread().isInterrupted());});t1.start();Thread.sleep(1000L);Object blocker = LockSupport.getBlocker(t1);System.out.println("t1 线程的blocker:"+blocker);Thread.sleep(1000*100L);}
}

执行结果

LockSupport.park(Object blocker); 方法可以在park线程的时候,传一个Object参数。调用者在其他线程可以通过LockSupport.getBlocker(t1)参数。


总结

LockSupport.park()休眠线程,LockSupport.unpark()唤醒线程,两个方法配合使用。也可以通过LockSupport.parkNanos()指定休眠时间后,自动唤醒。
LockSupport.park()不会释放monitor锁。
线程被打断,LockSupport.park()不会抛出异常,也不会吞噬掉interrupt的状态,调用者可以获取interrupt状态,自行进行判断,线程是由于什么原因被唤醒了。
LockSupport.park()会是线程进入WAITING状态,而LockSupport.parkNanos(long nanos) 会进入TIMED_WAITING状态。
LockSupport.park(Object blocker)和LockSupport.getBlocker(t1)配合使用,可以进行自定义数据传输。

Java中的线程休眠大法系列(三)LockSupport.park()相关推荐

  1. JAVA中创建线程的三种方法及比较

    JAVA中创建线程的方式有三种,各有优缺点,具体如下: 目录 一.继承Thread类来创建线程 二.实现Runnable接口来创建线程 三.通过Callable和Future来创建线程 四.三种方式创 ...

  2. java sleep唤醒_详解Java中的线程让步yield()与线程休眠sleep()方法

    Java中的线程让步会让线程让出优先级,而休眠则会让线程进入阻塞状态等待被唤醒,这里我们对比线程等待的wait()方法,来详解Java中的线程让步yield()与线程休眠sleep()方法 线程让步: ...

  3. Java中创建线程的三种方式

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)继承Thread类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. ...

  4. Java多线程编程(1)--Java中的线程

    一.程序.进程和线程   程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码.它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文 ...

  5. 四十七、面试前,必须搞懂Java中的线程池ThreadPoolExecutor(上篇)

    @Author:Runsen @Date:2020/6/9 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...

  6. 不允许使用java方式启动_细品 Java 中启动线程的正确和错误方式

    细品 Java 中启动线程的正确和错误方式 前文回顾详细分析 Java 中实现多线程的方法有几种?(从本质上出发) start 方法和 run 方法的比较 代码演示:/** * * start() 和 ...

  7. 如何在java中实现线程_用代码说话:如何在Java中实现线程

    并发编程是Java语言的重要特性之一,"如何在Java中实现线程"是学习并发编程的入门知识,也是Java工程师面试必备的基础知识.本文从线程说起,然后用代码说明如何在Java中实现 ...

  8. Java中一个线程只有六个状态。至于阻塞、可运行、挂起状态都是人们为了便于理解,自己加上去的。...

    java中,线程的状态使用一个枚举类型来描述的.这个枚举一共有6个值: NEW(新建).RUNNABLE(运行).BLOCKED(锁池).TIMED_WAITING(定时等待).WAITING(等待) ...

  9. 万字图文 | 学会Java中的线程池,这一篇也许就够了!

    来源:一枝花算不算浪漫 线程池原理思维导图.png 前言 Java中的线程池已经不是什么神秘的技术了,相信在看的读者在项目中也都有使用过.关于线程池的文章也是数不胜数,我们站在巨人的肩膀上来再次梳理一 ...

最新文章

  1. 吴恩达老师深度学习视频课笔记:深度学习的实用层面
  2. 网络编程学习笔记(uname函数)
  3. 北京地铁线路图纯算法附带求极权值(原创) 性能提升版
  4. 结对-英文词频分析-开发环境搭建过程
  5. SQL Server数据库镜像的FailOver自动连接
  6. java中getlast_Java ArrayDeque getLast()用法及代码示例
  7. php atan2,atan2l - [ C语言中文开发手册 ] - 在线原生手册 - php中文网
  8. 计算机网络 —— 组网
  9. C++ STL bitset类常用函数的使用
  10. 微软Azure云计算服务主导全球
  11. 配置Spring.NET
  12. 编程精华资源(ITeye优秀专栏)大汇总
  13. 全国计算机一级2021选择题,2021年度全国计算机一级考试选择题试题与详细答案.doc...
  14. 3dXXX Android,Android横竖屏 mdpi hdpi xhdpi xxhdpi xxxhdpi
  15. OFD转PDF格式免费在线转换
  16. 从零搭建移动H5开发项目实战
  17. 关于修改WIFI代理后手机部分APP无法使用的解决办法
  18. vue的proxyTable的地址代理和重定向,配合nginx的地址代理问题
  19. 魔改《合成大西瓜》——附试玩链接
  20. Apache Drill Architecture Introduction

热门文章

  1. 速收藏!实拍你的蚂蚁森林,张张都是高清美图壁纸
  2. KJT-GY12TP耐高压接近开关
  3. 统计csv词频_中文词频统计与词云生成
  4. 树莓派终端配置WiFi、查IP、查WiFi名
  5. bzoj 2786 DP
  6. 世界淡水资源占水资源的多少_我国淡水资源在全球水资源占比6%,世界排名第四(分布不均)...
  7. 文字超出显示... css
  8. UVa 1572 Self-Assembly (拓扑排序)
  9. 利用VS2019:基于MFC对话框编写多功能计算器:0基础教程(应该是CSDN中代码最全的教程了)
  10. Yagi-Uda八木天线