当前位置: 首页 > news >正文

java线程中的常见方法(详解)

 方法简介

方法名

功能

说明

start()

启动一个新线程,在新的线程运行 run 方法中的代码

start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现IllegalThreadStateException

run()

新线程启动后会调用的方法

如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法,否则默认不执行任何操作。但可以创建 Thread 的子类对象,来覆盖默认行为

join()

等待线程运行结束

join(long n)

等待线程运行结束,最多等待 n 毫秒

getId()

获取线程长整型的 id

id 唯一

getName()

获取线程名

setName(String)

修改线程名

getPriority()

获取线程优先级

setPriority(int)

修改线程优先级

java中规定线程优先级是1~10 的整数,较大的优先级能提高该线程被 CPU 调度的机率

getState()

获取线程状态

Java 中线程状态是用 6 个 enum 表示,分别为:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED

isInterrupted()

判断是否被打断,

不会清除 打断标记

isAlive()

线程是否存活(还没有运行完毕)

interrupt()

打断线程

如果被打断线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除 打断标记 ;如果打断的正在运行的线程,则会设置 打断标记 ;park 的线程被打断,也会设置 打断标记

interrupted()

static,判断当前线程是否被打断

会清除 打断标记

currentThread()

static,获取当前正在执行的线程

sleep(long n)

static,让当前执行的线程休眠n毫秒,休眠时让出 cpu 的时间片给其它线程

yield()

static,提示线程调度器让出当前线程对CPU的使用

主要是为了测试和调试

 start 和 run

结论

如果在主线程中 直接调用run方法,这样其实并没有启动新线程,还是在用main线程来执行,并不能达到异步这样的效果。

使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码。

因此,启动一个线程必须用 start方法,再用新的线程去调用run方法。

示例:直接调用 run

public static void main(String[] args) {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug(Thread.currentThread().getName());FileReader.read(Constants.MP4_FULL_PATH);}};t1.run();log.debug("do other things ...");
}

输出结果

19:39:14 [main] c.TestStart - main

19:39:14 [main] c.FileReader - read [1.mp4] start ...

19:39:18 [main] c.FileReader - read [1.mp4] end ... cost: 4227 ms

19:39:18 [main] c.TestStart - do other things ...

可以看到,没有产生新线程,都是主线程,方法调用还是同步的,必须等 FileReader.read()方法执行完才能往下做“do other things ...” 

调用 start

将上面的 t1.run() 改成 t1.start()

输出

19:41:30 [main] c.TestStart - do other things ...

19:41:30 [t1] c.TestStart - t1

19:41:30 [t1] c.FileReader - read [1.mp4] start ...

19:41:35 [t1] c.FileReader - read [1.mp4] end ... cost: 4542 ms

 可以看到,产生了新线程t1,方法的调用是异步的,不用等FileReader.read()方法执行完,也能往下做“do other things ...”

sleep 与 yield

sleep

静态方法:

Thread.Sleep(1000);
//静态方法,让当前正在执行的线程进入休眠(暂时停止执行)指定的毫秒数。

作用:

调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)

注意:

在哪个线程里,就让那个线程睡眠,main方法中的thread.sleep()并不是使我们的子线程进入休眠,而是使我们的主线程进入休眠,因为sleep()方法是使当前线程进入休眠

睡眠结束后的线程未必会立刻得到执行

建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性,下面代码都是睡眠1秒,但是TimeUnit可读性更高,里面可以选时间的单位,而sleep就是用毫秒。

public static void main(String[] args) {Thread.sleep(1000);TimeUnit.SECONDS.sleep(1);
}

打断睡眠:

其它线程可以使用 interrupt 方法打断正在睡眠的线程,将其叫醒,这时 sleep 方法会抛出 InterruptedException

 

yield

英文意思是:让出、让步

调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程

具体的实现依赖于操作系统的任务调度器,如果没有其他线程,CPU空闲时,那么任务调度器会让其执行,也就是你别谦让了,没有其他人了,你来吧。

异同

都是让线程先不占用cpu

sleep是进入到 阻塞状态,yield是进入到 就绪状态,就绪状态的线程是可以被任务调度器调用执行的,但是阻塞状态的不可以。

sleep有时间参数,用于睡眠多少毫秒。yield没有时间参数

sleep应用:提高CPU效率

在没有利用cpu来计算时,不要让while(true)空转浪费cpu,这时可以使用yield或sleep来让出 cpu的使用权给其他程序

例如下面的代码,通常有些服务器端会有while (true)这样的循环来一直执行,接收请求并响应,但是如果一直while (true),那么CPU会一直执行它,导致大部分时间都是空转,所以加一个睡眠,不用睡眠太久,就可以让CPU的执行效率提高很多。

while (true){try {Thread.sleep(50);}catch (InterruptedException e){e.printStackTrace();}
}

join

作用

t1.join();

等待t1线程运行结束

为什么需要 join?

下面的代码执行,打印 r 是什么?

static int r = 0;
public static void main(String[] args) throws InterruptedException {test1();
}
private static void test1() throws InterruptedException {log.debug("开始");//t1 线程修改 静态变量r的值Thread t1 = new Thread(() -> {log.debug("开始");sleep(1);log.debug("结束");r = 10;});//t1 线程启动t1.start();//主线程进行打印log.debug("结果为:{}", r);log.debug("结束");
}

分析

因为主线程和线程 t1 是并行执行的,t1 线程需要 1 秒之后才能算出 r=10

而主线程一开始就要打印 r 的结果,所以只能打印出 r=0

解决方法

如何让主线程打印出最新的,也就是经过t1线程修改完毕后的r的值呢?

让主线程也进行睡眠?让主线程睡眠的时间久一点?这样显然不好,因为不好控制睡眠时间,而且t1线程睡眠完毕后不一定会被任务调度器马上调用,所以情况很复杂。

这时候就可以用 join解决这个问题:只需要在 t1.start(); 后面加上一个 t1.join(); 即可,这样主线程会等待t1线程执行完毕再执行。

有时效的 join

t1.join(1500);

interrupt

作用

可以打断正在运行的线程,也可以打断正在阻塞的线程。

  • 如果打断正在阻塞中的线程,那么会让线程进入阻塞状态
  • 如果打断正在运行的线程,那么就会打断之,但实际上不是强行打断,而是告诉其他线程:我要打断你,由其他线程决定自己是否要结束。

打断正在阻塞中的线程

打断 sleep,wait,join 的线程

这几个方法都会让线程进入阻塞状态

打断 sleep 的线程, 会清空打断状态,也就是打断状态变成false

以 sleep 为例

private static void test1() throws InterruptedException {Thread t1 = new Thread(()->{sleep(1);}, "t1");t1.start();sleep(0.5);//主线程先小等一会,让t1线程进入睡眠t1.interrupt();//主线程打断t1线程log.debug(" 打断状态: {}", t1.isInterrupted());//输出打断标记
}

输出

java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at cn.itcast.n2.util.Sleeper.sleep(Sleeper.java:8)
at cn.itcast.n4.TestInterrupt.lambda$test1$3(TestInterrupt.java:59)
at java.lang.Thread.run(Thread.java:745)
21:18:10.374 [main] c.TestInterrupt - 打断状态: false

打断正常运行的线程

打断正常运行的线程, 不会清空打断状态,也就是打断状态会变成true

private static void test2() throws InterruptedException {Thread t2 = new Thread(()->{while(true) {Thread current = Thread.currentThread();boolean interrupted = current.isInterrupted();if(interrupted) {log.debug(" 打断状态: {}", interrupted);break;}}}, "t2");t2.start();sleep(0.5);t2.interrupt();
}

输出

20:57:37.964 [t2] c.TestInterrupt - 打断状态: true

如果只写一个 while true ,里面没有判断的话,那么这个主线程是打断不了t2线程的。

因为interrupt实际上不能打断另一个线程,只是告诉那个线程:我要打断你,被打断的线程自己决定受不受其他线程打断。也就是将打断状态改成true,说明有其他线程要打断我。

所以可以在里面加一个if判断,如果interrupted是真,说明有其他线程要打断我,所以我自己结束好了。

打断park线程

打断 park 线程, 不会清空打断状态,也就是打断状态是true

例如下面的代码,主线程休眠之后,打断park线程

private static void test3() throws InterruptedException {Thread t1 = new Thread(() -> {log.debug("park...");LockSupport.park();log.debug("unpark...");log.debug("打断状态:{}", Thread.currentThread().isInterrupted());}, "t1");t1.start();sleep(0.5);t1.interrupt();
}

输出

21:11:52.795 [t1] c.TestInterrupt - park...

21:11:53.295 [t1] c.TestInterrupt - unpark...

21:11:53.295 [t1] c.TestInterrupt - 打断状态:true

如果打断标记已经是 true, 则 park 会失效 

private static void test4() {Thread t1 = new Thread(() -> {for (int i = 0; i < 5; i++) {log.debug("park...");LockSupport.park();log.debug("打断状态:{}", Thread.currentThread().isInterrupted());}});t1.start();sleep(1);t1.interrupt();
}

输出

21:13:48.783 [Thread-0] c.TestInterrupt - park...
21:13:49.809 [Thread-0] c.TestInterrupt - 打断状态:true
21:13:49.812 [Thread-0] c.TestInterrupt - park...
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态:true
21:13:49.813 [Thread-0] c.TestInterrupt - park...
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态:true
21:13:49.813 [Thread-0] c.TestInterrupt - park...
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态:true
21:13:49.813 [Thread-0] c.TestInterrupt - park...
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态:true

清除打断标记

可以使用 Thread.interrupted() 清除打断状态,清除打断状态就是让打断状态变成false,意思是这个线程没有被打断

不推荐使用的方法

这些方法已过时,容易破坏同步代码块,造成线程死锁

jdk源码中也有说,不推荐这些方法

  1. stop():停止线程运行
  2. suspend():挂起(暂停)线程运行
  3. resume() :恢复线程运行

守护线程

默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。

有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。

守护线程的例子

  1. java的垃圾回收器线程就是一种守护线程。
  2. Tomcat 中的 Acceptor 和 Poller 线程都是守护线程,所以 Tomcat 接收到 shutdown 命令后,不会等待它们处理完当前请求

将某个线程设置为守护线程的方法

thread.setDaemon(true);

log.debug("开始运行...");Thread t1 = new Thread(() -> {log.debug("开始运行...");sleep(2);log.debug("运行结束...");}, "daemon");
// 设置该线程为守护线程
t1.setDaemon(true);
t1.start();sleep(1);
log.debug("运行结束...");

输出

08:26:38.123 [main] c.TestDaemon - 开始运行... 
08:26:38.213 [daemon] c.TestDaemon - 开始运行... 
08:26:39.215 [main] c.TestDaemon - 运行结束...

相关文章:

java线程中的常见方法(详解)

方法简介 方法名 功能 说明 start() 启动一个新线程&#xff0c;在新的线程运行 run 方法中的代码 start 方法只是让线程进入就绪&#xff0c;里面代码不一定立刻运行&#xff08;CPU 的时间片还没分给它&#xff09;。每个线程对象的start方法只能调用一次&#xff0c;如…...

线程池参数配置

上次面试被人问到&#xff0c;如果是IO 密集型的任务&#xff0c;该如何配置合适的线程数&#xff0c;当初我说要按照IO具体的请求毫秒时间&#xff0c;来配置具体的线程数。 NthreadsNcpu*(1w/c) 公式中 W/C 为系统 阻塞率 w:等待时间 c:计算时间一般情况下&#xff0c;如果存…...

Spread for Winform 16.2.20231.0 (SP2) Crack

Spread for Winform 16.2.20231.0 (SP2)发布。此版本包含针对客户报告的问题的重要修复&#xff1a; 安装版本 16 后&#xff0c;FarPoint.Localization.dll 将丢失。 将数据绑定到 Spread 时会出现 InvalidOperationException。 通过 Spread Designer 设置的上标将不会保留。…...

Go程序结构

Go程序结构 1、名称 ​ 名称的开头是一个字母或下划线&#xff0c;且区分大小写。 实体第一个字母的大小写决定其可见性是否跨包&#xff1a; ​ 若名称以大写字母开头&#xff0c;它是导出的&#xff0c;对包外是可见和可访问的&#xff0c;可以被自己包以外的其他程序所引用…...

JAVA面试总结-Redis篇章(四)——双写一致性

JAVA面试总结-Redis篇章&#xff08;四&#xff09;——双写一致性 问&#xff1a;redis 做为缓存&#xff0c;mysql的数据如何与redis进行同步呢&#xff1f;第一种情况&#xff0c;如果你的项目一致性要求高的话 采用以下逻辑我们应该先删除缓存&#xff0c;再修改数据库&…...

赋能医院数字化转型,医院拍摄VR全景很有必要

医院有没有必要拍摄制作VR全景呢&#xff1f;近期也有合作商问我们这个问题&#xff0c;其实VR智慧医院是趋势、也是机遇。现在外面很多的口腔医院、医美机构等都开始引入VR全景技术了&#xff0c;力求打造沉浸式、交互式的VR智慧医院新体验&#xff0c;通过VR全景展示技术来助…...

Vue3项目中没有配置 TypeScript 支持,使用 TypeScript 语法

1.安装 TypeScript&#xff1a;首先&#xff0c;需要在项目中安装 TypeScript。在终端中运行以下命令 npm install typescript --save-dev2.创建 TypeScript 文件&#xff1a;在 Vue 3 项目中&#xff0c;可以创建一个以 .ts 后缀的文件&#xff0c;例如 MyComponent.ts。在这…...

数据可视化大屏拼接屏开发实录:屏幕分辨率测试工具

一、可视化大屏开发 在数据可视化大屏开发时&#xff0c;确定数据可视化大屏拼接屏的板块尺寸需要考虑以下几个因素&#xff1a; 屏幕分辨率&#xff1a;首先需要知道每个板块屏幕的分辨率&#xff0c;包括宽度和高度&#xff0c;这决定了每个板块上可以显示的像素数量。 数据…...

每日一题7.28 209

209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 本题应该是用前缀…...

Python + Playwright 无头浏览器Chrome找不到元素

用Python Playwright调试时&#xff0c;发现不用无头浏览器&#xff08;即headlessFalse&#xff09;代码能够运行成功&#xff0c;但是一用无头浏览器时&#xff08;即headlessTrue&#xff09;就会报错&#xff0c;提示找不到元素。换成Firefox浏览器又不会有这个问题&#…...

C++信号量与共享内存实现进程间通信

关于信号量和共享内存的相关知识可参考下面链接&#xff1a; 进程间通信方式介绍_夜雨听萧瑟的博客-CSDN博客 C 创建共享内存_c共享内存_夜雨听萧瑟的博客-CSDN博客 信号量SytemV与Posix信号量的介绍与用法_夜雨听萧瑟的博客-CSDN博客 直接上代码&#xff0c;代码如下&#…...

[Tools: Camera Conventions] NeRF中的相机矩阵估计

参考&#xff1a;NeRF代码解读-相机参数与坐标系变换 - 知乎 在NeRF中&#xff0c;一个重要的步骤是确定射线&#xff08;rays&#xff09;的初始点和方向。根据射线的初始点和方向&#xff0c;和设定射线深度和采样点数量&#xff0c;可以估计该射线成像的像素值。估计得到的…...

【sgUpload】自定义上传组件,支持上传文件夹及其子文件夹文件、批量上传,批量上传会有右下角上传托盘出现,支持本地上传图片转换为Base64image

特性&#xff1a; 支持批量上传文件、文件夹可自定义headers可自定义过滤上传格式可自定义上传API接口支持drag属性开启可拖拽上传文件、文件夹 sgUpload源码 <template><div :class"$options.name" :dragenter"isDragenter"><!-- 上传按钮…...

Kafka 实时处理Stream与Batch的对比分析

Kafka 实时处理Stream与Batch的对比分析 一、简介1. Kafka的定义和特点2. Kafka实时处理基础架构 二、Stream和Batch1. Stream和Batch的区别2. 对比Stream和Batch的优缺点Stream的优缺点Batch的优缺点 三、使用场景1. 使用场景对比Batch使用场景Stream使用场景 2. 如何选择Stre…...

Andriod开发性能优化实践

文章目录 内存优化布局优化网络优化图片优化内存泄露绘制优化 内存优化 在Android开发中&#xff0c;有一些实践可以帮助进行内存优化&#xff0c;以减少应用程序的内存占用和提高性能。以下是一些常见的内存优化实践&#xff1a; 使用合适的数据结构和集合&#xff1a;选择合…...

linux环境安装mysql数据库

一&#xff1a;查看是否自带mariadb数据库 命令&#xff1a;rpm -qa | grep mariadb 如果自带数据库则卸载掉重新安装 命令&#xff1a;yum remove mariadb-connector-c-3.1.11-2.el8_3.x86_64 二&#xff1a;将压缩文件上传到/user/local/mysql文件夹 或者直接下载 命令&a…...

【深度学习中常见的优化器总结】SGD+Adagrad+RMSprop+Adam优化算法总结及代码实现

文章目录 一、SGD&#xff0c;随机梯度下降1.1、算法详解1&#xff09;MBSGD&#xff08;Mini-batch Stochastic Gradient Descent&#xff09;2&#xff09;动量法&#xff1a;momentum3&#xff09;NAG(Nesterov accelerated gradient)4&#xff09;权重衰减项&#xff08;we…...

山东大学软件学院考试回忆——大二上

文章目录 学习科目整体回忆上课考试回忆Web技术大学物理概率与统计计算机组织与结构离散数学&#xff08;2&#xff09;数据结构&#xff08;双语&#xff09; 学习科目 Web技术大学物理概率与统计计算机组织与结构离散数学&#xff08;2&#xff09;&#xff08;双语&#xf…...

【Express.js】异常分类和日志分级

异常分类和日志分级 第一章已经介绍过全局的异常处理了&#xff0c;但之前的做法过于简单&#xff0c;一股脑的捕获并返回。这一节我们将对异常进行细致的分类&#xff0c;并且日志也做标准化的分级。 准备工作 一个基础的 evp-express 项目 NodeJS Error 先了解一下 Node…...

k8s webhook实例,java springboot程序实现 对Pod创建请求添加边车容器 ,模拟istio实现日志文件清理

k8s webhook实例&#xff0c;java springboot程序实现 对Pod创建请求添加边车容器 &#xff0c;模拟istio实现日志文件清理 大纲 背景与原理实现流程开发部署my-docker-demo-sp-user服务模拟业务项目开发部署my-sidecar服务模拟边车程序开发部署服务my-docker-demo-k8s-opera…...

关于electron的问题汇总

1. electron-builder打包慢出错的问题 由于网络原因&#xff0c;在进行builder打包时&#xff0c;可能会等很长时间&#xff0c;直到最后还是以失败告终。 如果是第一次进行builder打包&#xff0c;会去下载winCodeSign、nsis、nsis-resources&#xff0c;往往都是第一个就卡住…...

ps 给衣服换色

可以通过色相饱和度来改变颜色 但如果要加强对比 可以通过色阶或曲线来调整 针对整体 调整图层-色相/饱和度 着色 给整个画面上色 选区-遮罩-取出来 然后调整图层-色相/饱和度也可以 或者以有图层-色相饱和度后 选区 按ctrli使其遮罩 同时按alt鼠标左键单机 ctrli反相…...

AI人工智能未来在哪里?2023年新兴产业人工智能有哪些就业前景?

AI人工智能未来在哪里&#xff1f;2023年新兴产业人工智能有哪些就业前景&#xff1f; 随着科技的不断发展&#xff0c;人工智能技术也在不断地进步。在数字化时代&#xff0c;人工智能技术已经渗透到了我们生活的各个方面。2023年为止中国产业80%已经实现半自动化&#xff0c;…...

组件间通信案例练习

1.实现父传子 App.vue <template><div class"app"><tab-control :titles["衣服","鞋子","裤子"]></tab-control><tab-control :titles["流行","最新","优选","数码&q…...

【matlab】机器人工具箱快速上手-正运动学仿真(代码直接复制可用)

安装好机器人工具箱&#xff0c;代码复制可用&#xff0c;按需修改参数 1.建模 %%%%%%%%SCARA机器人仿真模型 l[0.457 0.325]; L(1) Link(d,0,a,l(1),alpha,0,standard,qlim,[-130 130]*pi/180);%连杆1 L(2)Link(d,0,a,l(2),alpha,pi,standard,qlim,[-145 145]*pi/180);%连杆…...

论文解读|PF-Net:用于 3D 点云补全的点分形网络

原创 | 文 BFT机器人 01 背景 从激光雷达等设备中获取的点云往往有所缺失&#xff08;反光、遮挡等&#xff09;&#xff0c;这给点云的后续处理带来了一定的困难&#xff0c;也凸显出点云补全作为点云预处理方法的重要性。 点云补全&#xff08;Point Cloud Completion&#x…...

网络安全(零基础)自学

一、网络安全基础知识 1.计算机基础知识 了解了计算机的硬件、软件、操作系统和网络结构等基础知识&#xff0c;可以帮助您更好地理解网络安全的概念和技术。 2.网络基础知识 了解了网络的结构、协议、服务和安全问题&#xff0c;可以帮助您更好地解决网络安全的原理和技术…...

Spring Security 身份验证的基本类/架构

目录 1、SecurityContextHolder 核心类 2、SecurityContext 接口 3、Authentication 用户认证信息接口 4、GrantedAuthority 拥有权限接口 5、AuthenticationManager 身份认证管理器接口 6、ProviderManager 身份认证管理器的实现 7、AuthenticationProvider 特定类型的…...

市值超300亿美金,SaaS独角兽Veeva如何讲好中国故事?

“全球前50的药企&#xff0c;有47家正在使用Veeva。” 提到Veeva Systems&#xff08;以下简称“Veeva”&#xff09;&#xff0c;可能很多人并不熟悉。但是生命科学业内人士都知道&#xff0c;Veeva是全球头部的行业SaaS服务商。以“为生命科学行业构建行业云”为使命&#x…...

编译内联导致内存泄漏的问题定位修复

作者&#xff1a;0x264 问题 线上长时间存在一个跟异步 inflate 相关的量级较大的内存泄漏&#xff0c;如下所示&#xff1a; 第一次分析 从内存泄漏粗略看有几个信息&#xff1a; 被泄漏的Activity有很多&#xff0c;所以可能跟某个具体业务的关系不大引用链特别短&#xf…...