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 ...
随机推荐
- Vue.js高效前端开发 • 【Ant Design of Vue框架基础】
全部章节 >>>> 文章目录 一.Ant Design of Vue框架 1.Ant Design介绍 2.Ant Design of Vue安装 3.Ant Design o ...
- Mybatis获取自增主键的值
pojo: public class User { private Integer id; private String name; private String pwd; setter和getter ...
- POI导入导出Excel(HSSF格式,User Model方式)
1.POI说明 Apache POI是Apache软件基金会的开源代码库, POI提供对Microsoft Office格式档案读和写的功能. POI支持的格式: HSSF - 提供读写Microso ...
- APP自动化,怎样让应用不重置?
noReset =True产生的背景: 在编写APP自动化代码时,除了登录用例需要填写账号和密码外,其余很多用例都是需要先登录再操作的,如果每一个用例都从头开始到具体的操作,这样将会耗费很多时间,此时 ...
- JMeter_请求header
在接口调试的时候,请求参数确认正确无误,但是请求失败! 通过对比header,发现header缺少一些字段(token)以及传入的值不正确(Content-Type) 增加这些字段信息后,接口调试成功 ...
- centos7 自动交互expect 安装使用
1.安装 https://www.cnblogs.com/rocky-AGE-24/p/7256800.html 安装expect命令 两种方式yum安装 yum -y install expect ...
- springMVC+redis+redis自定义工具类 的配置
1. maven项目,加入这一个依赖包即可, <dependency> <groupId>redis.clients</groupId> <artifactI ...
- webSocket 前端 js 加入 心跳机制 的基本写法
1前言 websocket 一般 每隔 90 秒无操作则会自动断开 ,需要加入一个心跳机制 来防止 自断 2. 实验过程 (1)设定一个jsp 或html 文件都行 ,加入元素 (2)js 源码 , ...
- Word2010制作自动目录
原文链接:https://www.toutiao.com/i6488296610873737741/ 原文从网上复制: 查看"开始"选项卡,"样式"功能组,我们 ...
- Servlet部署描述符
注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6512237744641540612/ <Servlet简单实现开发部署过程>中的过程,可以概括为以下模 ...