2023.10.8 基本 Thread 线程详解

目录

Thread 常见构造方法

Thread 常见属性

创建一个 Thread 线程 

使用 jconsole 命令观察线程

中断一个 Thread 线程 

等待一个 Thread 线程 

休眠当前  Thread 线程 

让出当前 Thread 线程的 CPU 资源

线程的状态 


Thread 常见构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象并命名(可重名)
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象并命名
Thread(ThreadGroup group,Runnable target)线程可以被用来分组管理,分好的组即为线程组(了解即可)

注意:

  • 当线程被创建时,如果程序员不主动为其命名,JVM 将默认命名为 thread-0、 thread-1、 thread-2 等
  • 主动为线程命名最大的目的就是为了方便程序员调试

Thread 常见属性

属性获取方法解释
IDgetId()获取线程的 ID,为线程的唯一标识
名称getName()构造方法中起的名字
状态getState()获取线程的状态
优先级getPriority()获取线程的优先级,优先级可设置,但作用不大
是否后台线程isDaemon()代码中手动创建的线程和 main 默认为前台线程
内核线程是否存活isAlive()Thread 对象 从调用 start 方法到线程 run 方法执行完,isAlive() 为 true
是否被中断isInterrupted()判断线程是否被中断
返回对象引用currentThread()返回当前线程对象的引用

创建一个 Thread 线程 


可点击下方链接了解 7种创建线程 的方法

创建线程的七种方法


  • 此处简单举例 
//先创建一个类 让该类继承 Thread 父类
class MyThread extends Thread {
//    重写 run 方法@Overridepublic void run() {System.out.println("在 run方法中 自定义线程的工作内容");}
}public class ThreadDemo1 {public static void main(String[] args) {
//        创建实例tThread t = new MyThread();
//        启动并创建新线程t.start();
//        调用 run 方法仅执行 run 方法中的代码,并不会创建一个新线程
//        t.run();}
}

注意:

  • 仅调用 start 方法,系统内核才会真正创建一个线程
  • 当 run 方法运行完,内核中的线程会销毁,但是 Thread 对象 t 还会存在

使用 jconsole 命令观察线程

  • 我们需要借助 JDK,JDK 为 Java 开发工具安装包,其中包含很多工具

1.找到 jdk 安装目录并打开 jconsole

2.选择自己创建的程序并建立连接

  • 如果打开该页面,本地进程中啥也没有,我们可以使用管理员方式运行 jconsole 程序

3.选择不安全连接

4.查看线程


测试代码:

class TestThread extends Thread {@Overridepublic void run() {while (true) {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("这是 testThread ");}}
}public class ThreadDemo9 {public static void main(String[] args) {Thread t = new TestThread();t.start();while (true) {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("这是 main");}}
}

中断一个 Thread 线程 

  • 中断的意思并不是让线程立即停止,而是通知线程,其应该要停止了,是否真的停止取决于线程中的具体代码

方案一

  • 使用标志位来控制线程是否要停止
public class ThreadDemo10 {private static boolean flag = true;public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (flag) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();Thread.sleep(3000);
//        主线程这里可以随时通过flag 变量的取值 来操作 t 线程是否结束flag = false;}
}

运行结果:


方案二

  • 使用 Thread 自带的标志位来进行判定
  • 因为使用方案一 自定义变量的方式时,不能即使响应,如果 run 方法中 sleep 休眠的时间比较长,则会大大影响体验感
  • 使用 Thread 自带的标志位可以唤醒 sleep 方法
package Thread;public class ThreadDemo11 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();Thread.sleep(3000);
//        哪个对象调用 interrupt 方法就是终止哪个线程t.interrupt();}
}

运行结果:

  • 该代码为线程t 忽略了中断请求

适当修改 run 方法内部代码

  • 线程t 立即响应中断请求

  • 线程t 等待一定时间后进行中断操作

  • 当然也能加入其他代码,让线程 t 做点收尾工作再进行中断

总结:

  • 中断的意思并不是让线程立即停止,而是通知线程,其应该要停止了,是否真的停止取决于线程中的具体代码
  • sleep 之所以要清除标志位是因为当线程被唤醒后,该线程是否要中断,是立即中断还是稍后中断,由编写代码的程序员自己决定!

等待一个 Thread 线程 

  • 线程是随机进行调度的
  • 等待线程 做的事就是控制两个线程的结束顺序
public class ThreadDemo12 {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();}}});t.start();System.out.println("join 之前");//        此处的join 就是让当前的 main 线程来等待 t 线程执行结束(等待 t 的 run 方法执行完)t.join();System.out.println("join 之后");}
}

运行结果:

注意:

  • 如果执行 join 的时候,线程t 已经执行结束了,此时 mian线程 不会发生阻塞,会直接往下执行
  • 相对于上述代码中 join 的无参版本为死等,join 还有两种带参数的版本更常用,为了防止死等带来程序卡死之类的情况
join(long millis)指定一个最大等待时间
join(long millis, int nanos)nanos 参数表示要等待的额外纳秒数,精确度更高

休眠当前  Thread 线程 

  • 让线程休眠,本质上是让该线程不参与系统调度
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis 毫秒
public static void sleep(long millis, int nanos) throws InterruptedException提供更高精确度的休眠
  • 新创建出来的线程一般是放在 就绪队列 中
  • 当操作系统需要调度一个线程来执行时,就会从就绪队列中选一个
  • 当线程调用 sleep 方法时,该线程就会从 就绪队列 进入阻塞队列,暂时不参与 CPU 的调度执行
  • 但是线程的调度是不可控的,当 sleep 一定时间后线程重写回到就绪队列中时,不能保证其立即被 CPU 调度执行,所以该线程实际的休眠时间大于等于参数设置的休眠时间

让出当前 Thread 线程的 CPU 资源

  • 通过 Thread.yield() 方法来暂停当前正在执行的线程(让出当前的 CPU 资源,并执行其他线程)
  • yiled 方法不会改变线程的状态,只是让该线程从 在 CPU 中正在执行 转变为 回到就绪队列中重写排队参与调度
  • 因为线程具有抢占式执行,随机调度的特点
  • yield 方法无法完全保证当前线程能够让出 CPU 资源,因为可能刚进入就绪队列,又被CPU 调度执行了

线程的状态 

  • NEW:创建了 Thread 对象,但是还没调用 start 方法(内核中还未创建对应的 PCB)
  • TERMINATED:表示内核中的 PCB 已经执行完毕,但是 Thread 对象还在,且一个线程只能 start 一次!
  • RUNNABLE:表示可运行的(正在 CPU 上执行的 + 在就绪队列上随时可被调度的)
  • WAITING:特殊的阻塞,调用 wait 方法
  • TIMED_WAITING: 按照一定时间进行阻塞,调用 sleep 方法
  • BLOCKED: 等待锁的时候进入阻塞状态

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

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

相关文章

天然泉水除砷技术解析,除砷树脂

天然地下水和地表水都可能含有砷&#xff0c;地下水含砷量高于地表水。而地下水砷超标的原因一种是由于自然原因造成的&#xff0c;主要是含砷矿物风化溶解造成的地下水污染。由于含砷矿物分布广泛&#xff0c;这种污染在世界各地都有发生&#xff0c;尤其在南亚、南美等地区&a…

java基础 日期工具类

目录结构&#xff1a; DateUtils.java package dateStudy; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;public class DateUtils {private static final String FORMAT_1"yyyy-MM-dd HH:mm:ss";//私有方法&#xf…

如何正确方便的理解双指针?力扣102 (二叉树的层序遍历)

双指针&#xff0c;顾名思义就是指针的指针。 在此之前我们需要先理解单指针 &#xff08;简称为指针&#xff09;。指针很简单&#xff0c;直接上例子&#xff1a;例&#xff1a;现有两个变量&#xff0c;a10,b20. 要求&#xff1a;交换他们的值&#xff0c;输出的结果应为a20…

Flink之Watermark源码解析

1. WaterMark源码分析 在Flink官网中介绍watermark和数据是异步处理的,通过分析源码得知这个说法不够准确或者说不够详细,这个异步处理要分为两种情况: watermark源头watermark下游 这两种情况的处理方式并不相同,在watermark的源头确实是异步处理的,但是在下游只是做的判断,这…

LLaVa大模型关键技术及在线演示

LLaVA&#xff0c;一种新的大型多模态模型&#xff0c;称为“大型语言和视觉助手”&#xff0c;旨在开发一种通用视觉助手&#xff0c;可以遵循语言和图像指令来完成各种现实世界的任务。 这个想法是将 GPT-4 等大型语言模型 (LLM) 的强大功能与 CLIP 等视觉编码器相结合&#…

【MATLAB源码-第45期】基于matlab的16APSK调制解调仿真,使用卷积编码软判决。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. 16APSK调制解调 16APSK (16-ary Amplitude Phase Shift Keying) 是一种相位调制技术&#xff0c;其基本思想是在恒定幅度的条件下&#xff0c;改变信号的相位&#xff0c;从而传送信息。 - 调制&#xff1a;在16APSK中&am…

Transformer预测 | Pytorch实现基于Transformer的锂电池寿命预测(NASA数据集)

文章目录 效果一览文章概述模型描述程序设计参考资料效果一览 文章概述 Pytorch实现基于Transformer 的锂电池寿命预测,环境为pytorch 1.8.0,pandas 0.24.2 随着充放电次数的增加,锂电池的性能逐渐下降。电池的性能可以用容量来表示,故寿命预测 (RUL) 可以定义如下: SOH(t…

golang gin——controller 模型绑定与参数校验

controller 模型绑定与参数校验 gin框架提供了多种方法可以将请求体的内容绑定到对应struct上&#xff0c;并且提供了一些预置的参数校验 绑定方法 根据数据源和类型的不同&#xff0c;gin提供了不同的绑定方法 Bind, shouldBind: 从form表单中去绑定对象BindJSON, shouldB…

CTR特征建模:ContextNet MaskNet(Twitter在用的排序模型)

在之前的文章中 FiBiNet&FiBiNet模型&#xff0c;阐述了微博在CTR特征(Embedding)重要性建模方面的一些实践方向&#xff0c;今天再来学习下这个方面的两个相关研究&#xff1a;致力于特征和特征交互精炼(refine)的ContextNet和MaskNet&#xff0c;其中MaskNet也是Twitter(…

Unity 捕鱼游戏开发教程与源码

效果图展示 项目分析 主要功能点&#xff1a; 鱼的移动路线 这里使用简单移动的方式&#xff1a;随机位置然后随机鱼直线或者每帧更新鱼的角度实现走圆形。枪随着鼠标或点击位置移动 这个用坐标转换参考代码 private void Update(){Vector3 mousePos; // 鼠标位置// RectTra…

代码随想录Day15 二叉树 LeetCodeT513 找树左下角的值 T112路径总和 T106 从中序和后序遍历构造二叉树

以上思路来自于:代码随想录 (programmercarl.com) LeetCode T513 找树左下角的值 题目思路: 本题思路:这题我们使用递归法和迭代法解决问题 注意:左下角的值不一定就是一直向左遍历的叶子结点的值,首先可以确定是最后一行的第一个叶子结点的值,也就是最大深度的叶子结点的值 定…

【JavaEE】多线程(五)- 基础知识完结篇

多线程&#xff08;五&#xff09; 文章目录 多线程&#xff08;五&#xff09;volatile关键字保证内存可见性JMM&#xff08;Java Memory Model&#xff09; 不保证原子性 wait 和 notifywait()notify()线程饿死 上文我们主要讲了 synchronized以及线程安全的一些话题 可重入…

Unity设计模式——装饰模式

装饰模式&#xff08;Decorator&#xff09;&#xff0c;动态地给一个对象添加一些额外的职责&#xff0c;就增加功能来说&#xff0c;装饰模式比生成子类更为灵活。 Component类&#xff1a; abstract class Component : MonoBehaviour {public abstract void Operation(); …

网络层协议—IP协议

网络层协议—IP协议 文章目录 网络层协议—IP协议网络层简介IP协议简介IP协议文格式IP协议报头实现网络互联的使用设备 网段划分IP地址划分子网掩码IP地址的特点特殊的IP地址IP地址的数量限制私有IP地址和公网IP地址NAT技术 路由报文的分片与组装IP地址和硬件地址 网络层简介 …

Spring 统一处理(JavaEE进阶系列6)

目录 前言&#xff1a; 1.用户登录权限的校验 2.Spring拦截器 2.1自定义拦截器 2.2将自定义拦截器加入到系统配置 2.3拦截器练习 2.4拦截器的实现原理 3.统一异常处理 4.统一数据的返回格式 结束语&#xff1a; 前言&#xff1a; 接下来就是Spring Boot中的统一功能…

对于使用win32 API获取性能计数器的理解

微软提供了获取性能计数器的接口&#xff0c;如下 LSTATUS RegQueryValueExA([in] HKEY hKey,[in, optional] LPCSTR lpValueName,LPDWORD lpReserved,[out, optional] LPDWORD lpType,[out, optional] LPBYTE lpData,[in, out, optional] L…

mysql面试题30:什么是数据库连接池、应用程序和数据库建立连接的过程、为什么需要数据库连接池、你知道哪些数据库连接池

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:什么是数据库连接池? 数据库连接池是一种用于管理和复用数据库连接的技术。它是在应用程序和数据库之间建立一组数据库连接,并以池的形式存储起…

Kubernetes革命:云原生时代的应用编排和自动化

文章目录 什么是Kubernetes以及为何它备受欢迎&#xff1f;云原生应用和K8s的关系Kubernetes的核心概念&#xff1a;Pods、Services、ReplicaSets等部署、扩展和管理应用程序的自动化容器编排的演进&#xff1a;Docker到Kubernetes实际用例&#xff1a;企业如何受益于K8s的应用…

winform窗体控件太多显示不过来,怎么实现滚动条

winform窗体控件太多显示不过来&#xff0c;怎么实现滚动条 Winform Panel实现滚动条 一、创建panel 在界面上拖拽一个父级Panel1&#xff0c;然后在Panel1里面拖拽一个子级Panel2 设置父级Panel1的AutoScroll属性为True 属性设置好后&#xff0c;当子级高度或者宽度大于父…