Thread类及线程的核心操作

一. Thread类的常见构造方法

1. Thread()

Thread类无参的构造方法, 用于创建Thread类的实例对象.

2. Thread(String name)

带一个参数的Thread类构造方法, 创建一个线程对象, 并给其命名.

[注]: 如果不专门给线程命名, 那么线程默认的名字就是Thread-0, Thread-1, Thread-2 ...... , 给线程取名字, 不会影响到线程的执行效果, 为线程取一个合适的名字, 有利于调试程序.

3. Thread(Runnable target)

带一个参数的Thread类构造方法, 使用Runnable对象来创建线程对象.

4. Thread(Runnable target, String name) 

带两个参数的Thread类构造方法, 使用Runnable对象来创建一个线程对象, 并给其命名.

5. Thread(ThreadGroup group, Runnable target)

[了解] 带两个参数的Thread类构造方法, 使用Runnable对象来创建线程, 并将线程分成线程组. 设置线程组是为了方便统一设置线程的一些属性, 现在实际开发中很少使用线程组, 而是使用"线程池". 所以, 该构造方法我们了解即可.

二. Thread类几个常见属性和方法

1. Id

ID是Thread对象的身份标识, 是JVM自动分配的, 不能手动设置. 是Thread对象的身份标识. 使用getId()方法可以获取Thread对象的ID.

[注意]: ID是Thread对象的身份标识, 而不是线程的身份标识!!!  通常情况下, 一个Thread对象应该是对应到系统内核的一个线程上的, 但是也有可能Thread对象创建好了, 却没有启动这个线程, 那么此时系统内核就没有这个线程. 或者线程已经销毁了, 但是Thread对象还在.

2. name

线程名称, 使用getName()方法可以获取线程的name.

3. state

线程状态, 是JVM自动分配的, 不能手动设置. "就绪/阻塞 ... 都是进程的状态".

4. priority

进程优先级.

5. isDaemon()

是否为后台线程. (一个线程如果没有指定, 那么默认它是前台线程)

这里我们要辨析一下, 什么是"后台线程", 什么是"前台线程", 以及这两者之间有什么区别.

(1) 前台线程

        概念: 如果某线程在执行过程中能够控制线程结束, 那么这个线程就是前台线程.

        特点: 前台线程宣布进程结束, 此时进程立即结束, 后台线程也会随之结束.  前台线程没有宣布结束, 后台线程即使结束了也不影响进程继续执行.

(2) 后台线程

        概念: 如果某个线程在执行过程中不能控制线程结束, 那么这个线程就是后台线程. (例如: 虽然某个后台线程正在执行, 但是此时进程要结束了, 那么后台线程也会随之结束.)

        特点: 进程要结束(前台线程要结束), 后台线程无力阻止, 也会随之结束. 后台线程先结束了, 也不影响进程的继续执行(其他前台线程的继续执行).

通过上述分析, 我们可以理解为, 前台线程就是"话事人", 而后台线程就是一个"小透明". 前台线程的一举一动都影响着整个进程的状态, 而后台线程是否结束则对整个进程丝毫没有影响.

6. isAlive()

是否存活.

这里isAlive()表示的是内核中的线程是否存活. 为true表示内核中的线程存在, 为false表示内核中的线程不存在了.

7. isInterrupted()

线程是否被中断.

我们可以通过代码演示一下上述几个属性方法.

public class Demo4 {public static void main(String[] args) {Thread t = new Thread(new Runnable(){@Overridepublic void run() {for (int i = 0; i < 3; i++){System.out.println("hello thread");}}});System.out.println(t.getId());//获取线程IDSystem.out.println(t.getName());//获取线程名称System.out.println(t.getState());//获取线程状态System.out.println(t.getPriority());//获取线程优先级System.out.println(t.isDaemon());//是否为后台线程System.out.println(t.isAlive());//是否存活System.out.println(t.isInterrupted());//是否被终止t.start();}
}

代码运行结果如下:

 

三. 线程的几个核心操作

1. 启动一个线程 -- start()

start() 方法由一个线程对象调用, 表示启动该线程. 一旦start()方法执行完毕, 新线程就会立即开始执行. 调用start() 的线程也会继续执行.

例如: 我们在main方法中用t调用了start()方法, 相当于启动了一个新线程t, 从此刻开始, 线程"兵分两路", 一路继续执行main线程, 一路执行新的t线程, 两个线程并发执行. 示意图如下:

[注意]: 由于一个Thread对象只能对应内核中的一个线程, 所以一个Thread对象只能调用一次start()方法(只能启动一次线程). 如果多次调用start()方法, 那么就会报错.

2. 终止一个线程 

例如, 我们现在有A, B两个线程. B正在运行, 而A想要B结束. 此时A要做的就是让B把它的run方法执行完, B线程自然就结束了. (注:  这里A不会直接强制终止B)

我们举如下示例: 设置一个isRunning变量. isRunning为true, 则表示t线程在运行; isRunning为false, 则表明线程结束.

public class Demo7 {private static boolean isRunning = true;public static void main(String[] args) {// boolean isRunning = true;Thread t = new Thread(() -> {while (isRunning) {   // 如果t线程运行, 则执行while中的任务System.out.println("hello thread");try {Thread.sleep(1000);  // 每隔1000ms打印一次"hello thread"} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("t 线程结束");});t.start();try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}// 3s 之后, 主线程修改 isRunning 的值, 从而通知 t 结束.System.out.println("控制 t 线程结束");isRunning = false; //将isRunning置为false, 表示控制t线程结束.}
}

这段代码运行结果如下:

 

 

当然, 由于线程的终止是一个"比较温和"的操作, 所以, 当A线程让B线程结束时, B可以自行选择: 立即结束 / 执行完当前任务再结束 / 无视A, 继续执行. 

public class Demo8 {public static void main(String[] args) {Thread t = new Thread(() -> {// t.isInterrupted();Thread currentThread = Thread.currentThread(); //currentThread是Thread类中的一个静态方法, 表示获取当前线程的引用while (!currentThread.isInterrupted()) { //isInterrupted是Thread类中的一个成员方法,用于检查线程是否已被中断.初始值是false, 表示线程没有被中断.System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// throw new RuntimeException(e);// e.printStackTrace();// balabala 写一些其他的逻辑之后, 再 break//break;}}});t.start();try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}t.interrupt();}
}

 interrupt方法, 能够设置标志位, 也能唤醒sleep等阻塞方法; sleep方法被唤醒后, 又能清除标志位.

上述代码中, 我们通过在catch中进行不同的操作, 可以实现不同的目的. 

(1) 无视A的命令, 继续执行: catch中什么都不做.

(2) 稍后结束线程: 线执行一系列收尾工作,在break/return.

(3) 立即结束线程: 直接break/return.

3. 等待一个线程 -- join

我们知道, 多个线程的并发执行, 实质上是一个"随机调度, 抢占式执行"的方式. 所以我们程序员并不能指定哪个线程先执行, 哪个线程后执行. 但是我们可以通过让一个线程等待另一个线程来控制哪个线程先结束, 哪个线程后结束. 这里的线程等待, 就要用到 join方法. 

例如: 现在计算机上正在执行两个线程a和b, 我们现在想要让a线程等待b线程执行完, a才能继续维往下执行.

基本语法是:

b.join ();

意思就是让a线程等待b线程执行结束, a再继续往下执行.

public class Demo10 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("thread end");});t.start();//启动t线程for (int i = 0; i < 5; i++) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("开始等待t线程");t.join(); // 此处在main线程中加一个t.join(), 表示main线程等待t线程执行结束后才能结束System.out.println("t线程执行结束, 等待完成");System.out.println("继续执行main线程后面的部分");System.out.println("main线程执行结束");}
}

  此处在main线程中加一个t.join(), 就表示main线程等待t线程执行完成之后继续才能执行main线程后面的任务.

那么我们可不可以让t线程等待main线程呢? 那当然也是可以的~

public class Demo9 {public static void main(String[] args) throws InterruptedException {Thread mainThread = Thread.currentThread();Thread t = new Thread(() -> {System.out.println("t线程开始等待");try {mainThread.join(); //在t线程中插入一个mainThread.join(), 表示让t线程等待main线程.} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("main线程执行结束, t线程结束等待, 准备开始执行t线程后面的内容");for (int i = 0; i < 3; i++) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t线程执行结束");});t.start();for (int i = 0; i < 5; i++) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("main线程执行结束");}
}

 ​​​那么此时的t线程就必须等main线程的任务全部执行完才能执行t线程后面的任务了. 上述代码执行结果如下: 

 

好, 既然两个线程之间可以相互等待, 那么一个线程能不能等待多个线程呢? 答案也是可以的~~

public class Demo11 {public static void main(String[] args) throws InterruptedException {Thread t2 = new Thread(() -> {for (int i = 0; i < 4; i++) {System.out.println("t2");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});Thread t1 = new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println("t1");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();t2.start();System.out.println("开始等待t1, t2");t1.join();t2.join();System.out.println("t1, t2执行完毕, main线程结束等待t1, t2");System.out.println("继续执行main后面的任务");System.out.println("main线程执行结束");}
}

上述代码执行结果如下:

 

注意: join()的作用是 保证被等待的线程能够先结束. 如果开始等待的时候, 发现被等待的线程已经结束了, 那么就不需要再等了. 

上述使用的join( ) 不带参数, 表示"死等", 只要被等待的线程不执行完毕, 就会持续阻塞, 不会继续往下执行. 但是这样的等待方式显然是不好的, 所以java还提供了一种带参数的形式: join( long millis) 参数表示最多等待millis毫秒, 如果在这段时间内等待还没有结束, 那么就不会再等了.

4. 获取当前线程的引用

使用Thread类的currentThread()方法, 表示获取当前线程的引用.

例如, 获取main线程的引用:

 在任何线程中, 在任何需要的时候, 都可以通过此方法, 拿到当前线程的引用.

5. 休眠当前线程

通过Thread类中的sleep()方法, 休眠当前线程. 某线程执行sleep(), 就会让该线程处于阻塞等待状态, 此时这个线程不参与CPU调度, 从而把CPU资源让出来, 给别人使用.

使用sleep()可以解决实际开发中某些线程CPU占用率过高的问题.

好的, 以上就是本篇博客的全部内容啦, 如果喜欢小编的文章, 可以点赞,评论,收藏~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/883892.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云腾五洲的智联引擎是什么?

智联引擎是成都云腾五洲科技有限公司旗下的数智化转型服务平台&#xff0c;它提供云边协同的分布式物联网平台引擎服务。这一平台以其强大的功能和灵活性&#xff0c;为全行业提供数智化转型的新动力&#xff0c;帮助企业在数智化升级中实现持续增长。 核心能力 智联引擎的核心…

网络编程 TCP编程 Linux环境 C语言实现

所有基于数据传输通信的程序&#xff0c;都会被分成两种角色&#xff1a; 1. 服务端&#xff1a;又称为服务器 server 提供一种通信服务的进程 基本工作过程是&#xff1a;1> 接收请求数据 2> 处理请求数据 3> 发送处理结果 2. 客户端&#xff1a;client 使用一种通…

【Qt聊天室客户端】个人信息界面功能开发

1. 加载个人信息 从DataCenter数据类中拿到个人信息相关数据&#xff0c;然后显示到窗口中即可 个人信息界面中所有功能的实现&#xff0c;都是通过按钮触发操作&#xff0c;然后通过网络请求与后台交互完成信息更新 实现 2. 修改昵称 实现逻辑分析 获取输入框的昵称&#xf…

加油-加油

A 时刻注意A可逆&#xff0c;直接除去

十分钟Linux中的epoll机制

epoll机制 epoll是Linux内核提供的一种高效I/O事件通知机制&#xff0c;用于处理大量文件描述符的I/O操作。它适合高并发场景&#xff0c;如网络服务器、实时数据处理等&#xff0c;是select和poll的高效替代方案。 1. epoll的工作原理 epoll通过内核中的事件通知接口和文件…

60V恒流IC SL8443B内置功率MOS 支持2.5A电流 降压LED恒流驱动芯片

一、概述 SL8443B是一款高性能的LED恒流驱动芯片&#xff0c;具有60V的耐压能力&#xff0c;适用于高电压应用场景。它内置了5A&#xff08;或说5V&#xff0c;根据上下文理解为功率等级&#xff09;的功率MOS&#xff0c;可以减少外部元件数量&#xff0c;降低成本&#xff0…

获得淘宝app商品详情原数据 API 券后价获取API

item_get_app_pro-获得淘宝app商品详情原数据 通过此API可以实现通过商品id获取商品详情页数据&#xff0c;包括券后价、主图、详情等等。 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameStr…

得计算题者得天下!软考系统集成计算题详解!

软考中级系统集成项目管理工程师考试一共有《综合知识》和《案例分析》两门科目&#xff0c;而在这两科中都会涉及到计算题&#xff0c;特别是案例分析中&#xff0c;计算题每次考试都会占到一道大题&#xff0c;共25分&#xff0c;占到了科目总分的1/4&#xff0c;所以对于系统…

访问jenkins页面报错

安装fontconfig 即可 yum install fontconfig -y 安装完之后重启jenkins systemctl restart jenkins 再访问

JDBC2(防止sql注入,数据库连接池)

防止SQL注入 sql注入&#xff1a;利用sql语句的语法特点&#xff0c;应用层输入特殊格式&#xff0c;让原有的sql语句失效 创建表结构 并加入数据 create table login(lid int primary key auto_increment,lname varchar(20),lpwd varchar(20),lsex varchar(2),laddr varcha…

SpringBoot多线程

永线程池就不会内存泄漏&#xff0c;否则一直创建线程了&#xff08;如果业务量大很危险了&#xff0c;中断报警…&#xff1f;&#xff09; 【EnableAsync实现异步任务&#xff0c;简单用法】-CSDN博客 两种方法: 1、在启动类上加EnableAsync注解(Async默认的线程池是Simpl…

Linux——五种IO模型

目录 一IO基本理解 二五种IO模型 1五种IO模型示意图 2同步IO和异步IO 二非阻塞IO 1fcntl 2实现非阻塞IO 三多路复用 1select 1.1定位和作用 1.2介绍参数 1.3编写多路复用代码 1.4优缺点 2poll 2.1作用和定位 2.2介绍参数 2.3修改select代码 3epoll 3.1介绍…

[论文阅读]SimCSE: Simple Contrastive Learning of Sentence Embeddings

SimCSE&#xff1a;句子嵌入的简单对比学习 SimCSE: Simple Contrastive Learning of Sentence Embeddings http://arxiv.org/abs/2104.08821 EMNLP 2021 文章介绍了SimCSE&#xff0c;这是一种简单的对比学习框架&#xff0c;采用了自监督来提升模型的句子表示能力 而自监…

【网络原理】——图解HTTPS如何加密(通俗简单易懂)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;HTTP为什么不安全 二&#xff1a;HTTPS加密过程 1&#xff1a;密码学中的概念 &…

apt的编译安装(古老通讯)

Ubuntu系统的防火墙关闭&#xff1a; ufw disable 第一步&#xff1a;Ubuntu 安装依赖环境 apt -y install libpcre3-dev zlib1g-dev libssl-dev build-essential 如果出现无法下载则在末尾处假如 --fix missing如下图所示 出现下图则为安装成功 第二步&#xff1a; useradd…

上市公司企业数字金融认知数据集(2001-2023年)

一、测算方式&#xff1a;参考C刊《经济学家》王诗卉&#xff08;2021&#xff09;老师的做法&#xff0c;数字金融认知使用每万字年报描述中包含的对数字金融相关关键词的提及次数&#xff0c;关键词为&#xff1a;互联网、数字化、智能、大数据、电子银行、金融科技、科技金融…

LivePortrait——生成可拼接和重定向控制的高效肖像动画翻译

文章目录 原文翻译Abstract1. Introduction2. Related Work2.1. Non-diffusion-based Portrait Animation2.2. Diffusion-based Portrait Animation 3. Methodology3.1. Preliminary of Face Vid2vid3.2. Stage I: Base Model Training3.3. Stage II: Stitching and Retargetin…

快来免费参加交通领域重量级会议:第十三届交通运输研究(上海)论坛

一、会议简介 交通运输研究&#xff08;上海&#xff09;论坛&#xff08;简称为TRF&#xff09;是按照国际会议的组织原则&#xff0c;为综合交通运输领域学者们构建的良好 合作交流平台。交通运输研究&#xff08;上海&#xff09;论坛已经成功举办了十二届&#xff0c;凝聚了…

zabbix 6.0 监控clickhouse(单机)

zabbix 6.0 LTS已经包含了clickhouse的监控模板&#xff0c;所以我们可以直接使用自带的模板来监控clickhouse了。 0.前置条件 clickhouse 已经安装&#xff0c;我安装的是24.3.5.47zabbix-agent 已经安装并配置。系统是ubuntu 2204 server 1. 新建监控用户 使用xml的方式为…

RabbitMQ替换默认端口

前提&#xff1a;客户通过漏洞扫描&#xff0c;发现rabbitmq中的erlang是默认端口4369&#xff0c;出于安全的考虑&#xff0c;需要将erlang的端口修改为其他的端口。 1.查看默认erlang的默认端口 netstat -plnt | grep 4369 2.关闭rabbitmq rabbitmqctl stop&#xff08;注…