Thread中常用API
1、sleep方法
线程的 sleep 方法会使线程休眠指定的时间长度。休眠的意思是,当前逻辑执行到此不再继续执行,而是等待指定的时间。但在这段时间内,该线程持有的锁并不会释放。这样设计很好理解,因为线程在 sleep 的时候可能是处于同步代码块的中间位置,如果此时把锁放弃,就违背了同步的语义。所以 sleep 时并不会放弃锁,等过了 sleep 时长后,可以确保后面的逻辑还在同步执行。
sleep 方法有两个重载,分别是:
public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException
两者的区别只是一个支持休眠时间到毫秒级,另外一个到纳秒级。但其实第二个并不能真的精确到纳秒级别,我们来看第二个重载方法代码:
public static void sleep(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
可以清楚的看到,最终调用的还是第一个毫秒级别的 sleep 方法。而传入的纳秒会被四舍五入。
2、yield方法
yield方法意为让路,线程调用yield方法,则表明该线程愿意放弃占用的cpu资源,当然这只是给cpu提醒一下,如果cpu资源并不紧张,则会忽略该提醒,若cpu没有忽略这个提醒,该线程状态就由RUNNING 变为 RUNNABLE 状态,其他状态为RUNNABLE的线程可以抢夺cpu资源,该线程也可以加入抢夺cpu资源。开发中此方法并不常用。
3、currentThread 方法
这是一个静态方法,用于获取当前线程的实例。用法很简单,如下:
Thread.currentThread();
拿到线程的实例后,我们还可以获取 Thread 的 名称:
Thread.currentThread().getName();
此外我们还可以获取线程 ID :
Thread.currentThread().getId();
4、setPriority 方法
用于设置线程的优先级,优先级高的线程,更容易抢夺到资源,如果cpu资源比较空闲,优先级并没有什么作用,看下 setPriority 的源码:
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
Thread 有自己的最小和最大优先级数值,范围在 1-10。如果不在此范围内,则会报错。另外如果设置的 priority 超过了线程所在组的 priority ,那么只能被设置为组的最高 priority 。最后通过调用 native 方法 setPriority0 进行设置。
5、interrupt方法
interrupt方法意为中断,注意中断的并不是线程的逻辑,而是线程的阻塞。它并不会让线程中断,中断的是可中断方法,如sleep方法。
public class InterruptClient {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for(int i=0; i<100 ;i++){
System.out.println("I'm doing my work");
System.out.println("I'm interrupted?"+Thread.currentThread().isInterrupted());
}
});
thread.start();
Thread.sleep(1);
thread.interrupt();
}
线程 run 方法中没有调用可中断方法,只是输出 I’m doing my work,另外还会输出自己的中断状态。而主线程会 sleep 一毫秒,留时间给 thread 线程启动,然后调用 thread 线程的 interrupt 方法。截取其中关键一段输出如下:
I'm doing my work
I'm interrupted?false
I'm doing my work
I'm interrupted?true
I'm doing my work
I'm interrupted?true
这段后面的输出一直到结束,都在重复 “I’m doing my work I’m interrupted?true“,这说明两个问题:
- 调用 interrupt 方法,并不会影响可中断方法之外的逻辑。线程不会中断,会继续执行。这里的中断概念并不是指中断线程;
- 一旦调用了 interrupt 方法,那么线程的 interrupted 状态会一直为 ture(没有通过调用可中断方法或者其他方式主动清除标识的情况下);
通过上面实现了解了 interrupt 方法中断的不是线程。它中断的其实是可中断方法,如 sleep 。可中断方法被中断后,会把 interrupted 状态归位,改回 false 。
看代码:
public class InterruptSleepClient {
public static void main(String[] args) throws InterruptedException {
Thread xiaopang = new Thread(()->{
for(int i=0; i<100 ;i++){
System.out.println("I'm doing my work");
try {
System.out.println("I will sleep");
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("My sleeping was interrupted");
}
System.out.println("I'm interrupted?"+Thread.currentThread().isInterrupted());
}
});
xiaopang.start();
Thread.sleep(1);
xiaopang.interrupt();
}
执行结果如下:
I'm doing my work
I will sleep
My sleeping was interrupted
I'm interrupted? false
I'm doing my work
I will sleep
I'm interrupted? false
I'm doing my work
I will sleep
I'm interrupted? false
可以看到当 xiaopang.interrupt () 执行后,睡眠中的 xiaopang 被唤醒了。这里额外需要注意的是,此时 xiaopang 线程的 interrupted 状态还是 false 。因为可中断线程会捕获中断的信号,并且会清除掉 interrupted 标识。因此输出的 “I’m interrupted ?” 全部是 false 。
最后我们再看一下静态方法 interrupted 。这个方法其实和成员方法 isInterrupted 方法类似,都是返回了 interrupted 状态。不同就是 interrupted 方法返回状态后,如果为 true 则会清除掉状态。而 isInterrupted 则不会。上面第一段测试代码已经验证了这一点,被打断后,调用 isInterrupted 一直返回 true。
下面验证下 interrupted 是否会清除标识位。把第一段代码稍微改一下:
public class InterruptedClient {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for(int i=0; i<100 ;i++){
System.out.println("I'm doing my work");
//原代码 System.out.println("I'm interrupted?"+Thread.currentThread().isInterrupted());
System.out.println("I'm interrupted?"+Thread.interrupted());
}
});
thread.start();
Thread.sleep(1);
thread.interrupt();
}
}
输出结果如下:
I'm doing my work
I'm interrupted?false
I'm doing my work
I'm interrupted?false
I'm doing my work
I'm interrupted?true
I'm doing my work
I'm interrupted?false
I'm doing my work
I'm interrupted?false
可以看到在输出 “I’m interrupted?true” 后,中断状态又变回了 false。
通过以上,可以看出 interrupt 方法只是设置了中断标识位,这个标识位只对可中断方法会产生作用。不过我们还可以利用它做更多的事情,比如说如果线程的 run 方法中这么写:
while(!isInterrupted()){
//do somenting
}
这样主线程中可以通过调用此线程的 interrupt 方法,让其退出运行。此时 interrupted 的含义就真的是线程退出了。不过假如你的 while 循环中调用了可中断方法,那么就会有干扰。
6、join方法
最后我们再说一个重要的方法 join。这个方法功能强大,也很实用。我们用它能够实现并行化处理。比如主线程需要做两件没有相互依赖的事情,那么可以起 A、B 两个线程分别去做。通过调用 A、B 的 join 方法,让主线程 block 住,直到 A、B 线程的工作全部完成,才继续走下去。我们来看下面这段代码:
public class JoinClient {
public static void main(String[] args) throws InterruptedException {
Thread backendDev = createWorker("backed dev", "backend coding");
Thread frontendDev = createWorker("frontend dev", "frontend coding");
Thread tester = createWorker("tester", "testing");
backendDev.start();
frontendDev.start();
// backendDev.join();
// frontendDev.join();
tester.start();
}
public static Thread createWorker(String role, String work) {
return new Thread(() -> {
System.out.println("I finished " + work + " as a " + role);
});
}
}
这段代码中,我们把 join 方法去掉。执行结果如下:
I finished backend coding as a backed dev
I finished testing as a tester
I finished backend coding as a frontend dev
我们期望的是前端和后端开发完成工作后,测试才开始测试。但从输出结果看并非如此。要想实现这个需求,我们只需把注释打开,让 backendDev 和 frontendDev 先做 join 操作,此时主线程会被 block 住。直到 backendDev 和 frontendDev 线程都执行结束,才会继续往下执行。输出如下:
I finished backend coding as a backed dev
I finished frontend coding as a frontend dev
I finished testing as a tester
可以看到现在的输出完全符合我们的期望。可见调用 join 方法后 block 的并不是被调用的 backendDev 或 frontendDev 线程,而是调用方线程,这个需要牢记。
总结:
Thread还有其他的API,比如废弃的stop,关于其他的API可以阅读Thread源码,注释写的很详细。
Thread中常用API的更多相关文章
- kafka中常用API的简单JAVA代码
通过之前<kafka分布式消息队列介绍以及集群安装>的介绍,对kafka有了初步的了解.本文主要讲述java代码中常用的操作. 准备:增加kafka依赖 <dependency> ...
- Java 中 常用API概述之 Math, Object, String,StringBuffer类,Arrays,Integer类
Math Math类包含执行基本数字运算的方法,如基本指数,对数,平方根和三角函数. 与StrictMath类的一些数字方法不同,Math类的StrictMath所有Math都没有定义为返回比特位相同 ...
- Web javascript 中常用API合集
来源于:https://www.kancloud.cn/dennis/tgjavascript/241852 一.节点 1.1 节点属性 Node.nodeName //返回节点名称,只读 Node. ...
- java基础3.0:Java常用API
本篇介绍Java基础中常用API使用,当然只是简单介绍,围绕重要知识点引入,巩固开发知识,深入了解每个API的使用,查看JavaAPI文档是必不可少的. 一.java.lang包下的API Java常 ...
- elasticsearch中常用的API
elasticsearch中常用的API分类如下: 文档API: 提供对文档的增删改查操作 搜索API: 提供对文档进行某个字段的查询 索引API: 提供对索引进行操作,查看索引信息等 查看API: ...
- C++ 中超类化和子类化常用API
在windows平台上,使用C++实现子类化和超类化常用的API并不多,由于这些API函数的详解和使用方法,网上一大把.本文仅作为笔记,简单的记录一下. 子类化:SetWindowLong,GetWi ...
- Express ( MiddleWare/中间件 路由 在 Express 中使用模板引擎 常用API
A fast, un-opinionated, minimalist web framework for Node.js applications. In general, prefer simply ...
- 使用Word API打开Word文档 ASP.NET编程中常用到的27个函数集
使用Word API(非Openxml)打开Word文档简单示例(必须安装Word) 首先需要引入参照Microsoft.Office.Interop.Word 代码示例如下: public void ...
- JavaWeb学习之JDBC API中常用的接口和类
JDBC API中包含四个常用的接口和一个类分别是: 1.Connection接口 2.Statement接口 3.PreparedStatement接口 4.ResultSet接口 5.Driver ...
随机推荐
- 「Codeforces 724F」Uniformly Branched Trees
题目大意 如果两棵树可以通过重标号后变为完全相同,那么它们就是同构的. 将中间节点定义为度数大于 \(1\) 的节点.计算由 \(n\) 个节点,其中所有的中间节点度数都为 \(d\) 的互不同构的树 ...
- CS5202Capstone|CS5202芯片|CS5202芯片方案
一.CS5202功能概述CS5202结合了DisplayPort输入接口和模拟RGB DAC输出接口.嵌入式单片机基于工业标准8051核心,适用于多个细分市场和显示器应用程序,如笔记本电脑.主板.台式 ...
- 造轮子-strace(一)
见字如面,我是东北码农. 本文是造轮子-strace的第一篇,我们先介绍strace的功能.使用.下一篇我们来用代码实现一下strace的功能,造个轮子.今天我们先观察.使用轮子. 1.什么是stra ...
- 【MySQL作业】sum、max 和 min 聚合函数——美和易思聚合函数应用习题
点击打开所使用到的数据库>>> 1.统计商品最高单价和最低单价. -- 获取所有商品的最高单价和最低单价: select max(unitPrice) 最高单价 , min(unit ...
- 编写Java程序,使用菜单组件制作一个记事本编辑器
返回本章节 返回作业目录 需求说明: 使用菜单组件制作一个记事本编辑器 实现思路: 创建记事本菜单工具栏JMenuBar. 创建多个菜单条JMenu. 创建多个菜单项JMenuItem. 将菜单添加至 ...
- [ vue ] xxxProject项目杂记
2020.4.9 加入eCharts 2020.4.8 完成article的显示,其间碰到全局路由守卫写的有错误,导致跳转报错.已修复. 加入keep-alive功能,缓存视图数据 疑问:如果在全局组 ...
- CentOS7 安装mysql并解决安装慢的问题
0.centOS7 mini版安装及网络配置 //可从我的网盘保存下载,可用虚拟机安装 链接:https://pan.baidu.com/s/10_AHxN0DtJ75s1oFOaaZ3A 密码:ud ...
- Mysql设计遵循规则
为什么要优化系统的吞吐量瓶颈往往出现在数据库的访问速度上随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢数据是存放在磁盘上的,读写速度无法和内存相比 如何优化设计数据库时:数据库表. ...
- GNU C字节对齐__attribute__((aligned(n))) #pragma pack(n)
在阅读gnu软件c源代码时,经常会遇到字节对齐相关操作,比如uboot命令相关的代码中,会遇到__attribute__((aligned(n)))扩展关键字,#pragma pack(n)预处理指令 ...
- ProE许可、PTC许可、Creo许可、许可分析、分析许可
Pro/Engineer操作软件(又简称ProE)是美国参数技术公司(PTC)旗下的CAD/CAM/CAE一体化的三维软件,Creo是美国PTC公司于2010年10月推出CAD设计软件包,creo是P ...