Java中的线程休眠大法系列(三)LockSupport.park()
文章目录
- 前言
- 一、看看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()相关推荐
- JAVA中创建线程的三种方法及比较
JAVA中创建线程的方式有三种,各有优缺点,具体如下: 目录 一.继承Thread类来创建线程 二.实现Runnable接口来创建线程 三.通过Callable和Future来创建线程 四.三种方式创 ...
- java sleep唤醒_详解Java中的线程让步yield()与线程休眠sleep()方法
Java中的线程让步会让线程让出优先级,而休眠则会让线程进入阻塞状态等待被唤醒,这里我们对比线程等待的wait()方法,来详解Java中的线程让步yield()与线程休眠sleep()方法 线程让步: ...
- Java中创建线程的三种方式
Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)继承Thread类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. ...
- Java多线程编程(1)--Java中的线程
一.程序.进程和线程 程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码.它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文 ...
- 四十七、面试前,必须搞懂Java中的线程池ThreadPoolExecutor(上篇)
@Author:Runsen @Date:2020/6/9 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...
- 不允许使用java方式启动_细品 Java 中启动线程的正确和错误方式
细品 Java 中启动线程的正确和错误方式 前文回顾详细分析 Java 中实现多线程的方法有几种?(从本质上出发) start 方法和 run 方法的比较 代码演示:/** * * start() 和 ...
- 如何在java中实现线程_用代码说话:如何在Java中实现线程
并发编程是Java语言的重要特性之一,"如何在Java中实现线程"是学习并发编程的入门知识,也是Java工程师面试必备的基础知识.本文从线程说起,然后用代码说明如何在Java中实现 ...
- Java中一个线程只有六个状态。至于阻塞、可运行、挂起状态都是人们为了便于理解,自己加上去的。...
java中,线程的状态使用一个枚举类型来描述的.这个枚举一共有6个值: NEW(新建).RUNNABLE(运行).BLOCKED(锁池).TIMED_WAITING(定时等待).WAITING(等待) ...
- 万字图文 | 学会Java中的线程池,这一篇也许就够了!
来源:一枝花算不算浪漫 线程池原理思维导图.png 前言 Java中的线程池已经不是什么神秘的技术了,相信在看的读者在项目中也都有使用过.关于线程池的文章也是数不胜数,我们站在巨人的肩膀上来再次梳理一 ...
最新文章
- 吴恩达老师深度学习视频课笔记:深度学习的实用层面
- 网络编程学习笔记(uname函数)
- 北京地铁线路图纯算法附带求极权值(原创) 性能提升版
- 结对-英文词频分析-开发环境搭建过程
- SQL Server数据库镜像的FailOver自动连接
- java中getlast_Java ArrayDeque getLast()用法及代码示例
- php atan2,atan2l - [ C语言中文开发手册 ] - 在线原生手册 - php中文网
- 计算机网络 —— 组网
- C++ STL bitset类常用函数的使用
- 微软Azure云计算服务主导全球
- 配置Spring.NET
- 编程精华资源(ITeye优秀专栏)大汇总
- 全国计算机一级2021选择题,2021年度全国计算机一级考试选择题试题与详细答案.doc...
- 3dXXX Android,Android横竖屏 mdpi hdpi xhdpi xxhdpi xxxhdpi
- OFD转PDF格式免费在线转换
- 从零搭建移动H5开发项目实战
- 关于修改WIFI代理后手机部分APP无法使用的解决办法
- vue的proxyTable的地址代理和重定向,配合nginx的地址代理问题
- 魔改《合成大西瓜》——附试玩链接
- Apache Drill Architecture Introduction
热门文章
- 速收藏!实拍你的蚂蚁森林,张张都是高清美图壁纸
- KJT-GY12TP耐高压接近开关
- 统计csv词频_中文词频统计与词云生成
- 树莓派终端配置WiFi、查IP、查WiFi名
- bzoj 2786 DP
- 世界淡水资源占水资源的多少_我国淡水资源在全球水资源占比6%,世界排名第四(分布不均)...
- 文字超出显示... css
- UVa 1572 Self-Assembly (拓扑排序)
- 利用VS2019:基于MFC对话框编写多功能计算器:0基础教程(应该是CSDN中代码最全的教程了)
- Yagi-Uda八木天线