Java线程的创建与使用

线程的概念

线程是‌操作系统能够进行运算调度的最小单位,是进程中的实际运作单位‌。一个进程可以包含多个线程,每个线程是进程中一个单一顺序的控制流,并行执行不同的任务。

线程生命周期

线程的状态是指线程在执行过程中的不同阶段。以下是线程的几种常见状态介绍:

  1. 新建状态(New):当线程对象被创建但尚未启动时,线程处于这个状态。此时,线程已经有了相应的内存空间和其他资源,但还没有开始执行。

  2. 就绪状态(Runnable):线程已经被启动,并且准备好了运行,等待被线程调度器选中获取CPU的执行时间。在就绪状态的线程都等待在就绪队列中。

  3. 运行状态(Running):线程获得了CPU的执行时间,正在执行它的run()方法中的代码。线程调度器根据线程优先级和策略从就绪队列中选取线程进入运行状态。

  4. 阻塞状态(Blocked):线程因为某些原因暂时停止运行。例如,线程等待某个锁的释放,或者线程等待某些I/O操作完成。

  5. 等待状态(Waiting):线程等待其他线程执行特定操作(如通知)时进入此状态。线程在等待状态时不会被分配CPU执行时间。

  6. 超时等待状态(Timed Waiting):线程在一定时间内等待另一个线程的通知或某个特定操作完成。比如线程执行了sleep(1000)方法,如果超过了指定时间,线程会自动返回到就绪状态。

  7. 终止状态(Terminated):线程的run()方法执行完成后,线程进入终止状态。此时,线程已经完成了它的生命周期,并且不再参与线程调度。

了解线程的这些状态对于多线程编程中的调试和性能优化是非常重要的。

线程的等待、阻塞或者挂起都是指线程无法执行的状态,只不过等待更强调线程主动等待,而阻塞则更强调线程无法获取资源被动地等待,不用太纠结它们的区别,一般都统称为阻塞状态。

线程的基本操作

线程的创建
  • 继承Thread类:新建一个类继承Thread类,重写它的run()方法。
public class ThreadA extends Thread{@Overridepublic void run() {System.out.println("这里编写线程要做的事情");}public static void main(String[] args) {//1.新建实例并启动一个线程new ThreadA().start();//2.若无需复用也可以用匿名内部类实现new Thread(() -> {System.out.println("这里编写线程要做的事情");}).start();}
}
  • 实现Runnable接口:新建一个类实现Runnable接口,实现它的run()方法。
public class ThreadB implements Runnable{@Overridepublic void run() {System.out.println("这里编写线程要做的事情");}public static void main(String[] args) {new Thread(new ThreadB()).start();}
}
  • 实现Callable接口:这种方式可以获取线程执行的返回值。
public class ThreadC implements Callable<Integer> {@Overridepublic Integer call() throws Exception {System.out.println("这里编写线程要做的事情");return 10;//返回结果}public static void main(String[] args) throws Exception {ThreadC threadC = new ThreadC();FutureTask<Integer> task = new FutureTask<>(threadC);new Thread(task).start();System.out.println(task.get());//获取call()的返回结果}
}

创建线程的方式还有使用线程池,只不过线程池内部也是使用new Thread()方式创建线程的。其实这些所谓的线程都只是Java层面的,new Thread()只是创建了一个Java对象而已,真正操作系统层面的线程是调用start()方法之后才创建的。

线程的终止

一般来说,线程的run方法执行完毕就会自动终止,无须手工关闭。但不是所有线程都可以执行完毕的。比如一些服务端的后台线程可能会常驻系统,它们通常不会正常终结。或许它们的执行体本身就是一个死循环,用于提供某些服务。Thread提供了一个stop()方法。如果你使用stop()方法,就可以立即将一个线程终止,非常方便。但是这是一个废弃的方法,非常不推荐使用。原因是stop()方法过于暴力,强行把执行到一半的线程终止,可能会引起一些数据不一致的问题。

一种简单常见的方式是使用退出标志,在需要退出时通过别的线程将标志位exit设置成true,就能等run()方法执行完毕后自动退出,其中volatile关键字保证了其它线程对exit的改动是可见的。

public class ThreadService extends Thread {public volatile boolean exit = false; public void run() { while (!exit){//处理业务}}	 
}
线程中断

线程中断是一种重要的线程协作机制,Thread提供了3个相关的方法:

  • interrupt()中断线程
  • isInterrupted()判断线程是否被中断
  • interrupted()判断线程是否被中断并清楚中断状态

interrupt()的作用是设置线程的中断标志位,中断标志位可以中断阻塞状态,例如sleep()、wait()或IO等原因导致的线程阻塞,使其立即抛出中断异常,这就是为什么sleep()和wait()会声明一个受检异常InterruptedException,抛出异常后中断标志位会被清除。线程也可以利用isInterrupted()方法判断自己是否被中断,从而选择是否要退出。利用中断机制可以实现线程的优雅终止。

 public class ThreadService extends Thread {public void run() { while (!isInterrupted()){ //非阻塞过程中通过判断中断标志来退出try{Thread.sleep(5*1000);//阻塞过程捕获中断异常来退出}catch(InterruptedException e){e.printStackTrace();break;//捕获到异常之后,执行 break 跳出循环}}} }
其它方法
wait()方法

当一个线程调用一个共享变量的wait()方法时,该调用线程会被阻塞挂起,直到:

  1. 其他线程调用了该共享对象的notify()或者notifyAll()方法;
  2. 其他线程调用了该线程的interrupt()方法,该线程抛出InterruptedException异常返回。
  3. 等待超时
  4. 虚假唤醒,notify()方法可能会唤醒多个线程(理论上,实际不常发生)。

调用wait()方法会释放锁,既然要释放锁那必须得先拥有锁,所以wait()方法须在synchronized同步块中调用。

String a = "123";//共享变量
boolean waitFlag = true;//挂起判断条件
//先获取共享变量的锁
synchronized (a){while (waitFlag){//判断挂起条件,防止虚假唤醒a.wait();}
}
notify()和notifyAll()

notify()随机唤醒在此对象监视器上等待的单个线程,notifyAll()唤醒在此对象监视器上等待的所有线程。

join()

join() 在当前线程中调用A线程的 join() 方法,则当前线程转为阻塞状态,等待A线程执行完成。很多情况下,主线程生成并启动了子线程,需要用到子线程返回的结果,也就是需要主线程需要在子线程结束后再结束,这时候就要用到 join() 方法。实际工作中CountDownLatch是比join()更好的选择。

sleep()

使线程阻塞挂起指定的时间,但不会释放锁。

yield()

线程让出自己剩余的时间片,转入就绪状态。

守护线程

守护线程是一种特殊的线程,常用于后台完成一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程。如果你希望在主线程结束后JVM进程马上结束,那么在创建线程时可以将其设置为守护线程,如果你希望在主线程结束后子线程继续工作,等子线程结束后再让JVM进程结束,那么就将子线程设置为用户线程。可以调用线程的setDaemon(true)方法将线程设置成守护线程。

参考

《Java高并发程序设计》

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

数位dp(算法篇)

算法篇之数位dp 数位dp 概念&#xff1a; 数位dp是一种计数用的dp&#xff0c;一般是要统计一个区级[l,r]内满足一些条件的数的个数所谓数位dp&#xff0c;就是对数位进行dp&#xff0c;也就是个位、十位等相对于普通的暴力枚举&#xff0c;数位dp快就快在它的记忆化&#x…

打印机问题故障处理_十大打印机故障大全及处理方法

日常办公和生活中&#xff0c;打印机是不可或缺的重要设备。然而&#xff0c;在添加共享或使用共享打印机过程中&#xff0c;经常会遇各种问题。有遇到无法添加打印机、访问共享打印机报错&#xff0c;打印机无法打印等问题&#xff0c;然后这几种错误分别的原因不同&#xff0…

博睿谷IT认证-订阅试学习

在这个信息爆炸的时代&#xff0c;拥有一张IT认证证书&#xff0c;就像拿到了职场晋升的通行证。博睿谷&#xff0c;作为IT认证培训的佼佼者&#xff0c;帮你轻松拿下华为、Oracle等热门认证。下面&#xff0c;让我们一起看看博睿谷如何助你一臂之力。 学习时间&#xff0c;你说…

Fanuc modbusTcp 配置(Robo只能做从站)

需要刷modbusTcp功能包 581800 两个包 插口位置 1CD38A或2CD38B&#xff0c;ip地址可以是固定IP或DHCP IP的设置 MODB_ENBLIO1 才能读写io 注意通讯fanuc是 小端 DI DO都可以

C# 关于“您与该网站的连接不是私密连接...”的问题

目录 问题现象 范例运行环境 WebService 类 类介绍 增加参数 实现 小结 问题现象 最近在访问开发的微信支付功能时遇到了无法访问令牌的错误&#xff0c;这个错误是公司内部应用程序接口返回的访问错误。经过排查是访问 HTTPS 站点遇到的错误&#xff0c;提示证书风险…

MyBatis深度剖析:从入门到精通的实践指南

前言 什么是mybatis&#xff1f; MyBatis是一款优秀的持久层框架&#xff0c;用于简化Java应用程序与数据库之间的交互 什么是框架&#xff0c;为什么需要框架技术&#xff1f; 框架技术 是一个应用程序的半成品提供可重用的公共结构按一定规则组织的一组组件框架优势&#x…

Linux之实战命令05:find应用实例(三十九)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

node.js居家养老服务系统—计算机毕业设计源码35247

目 录 摘要 1 绪论 1.1选题的背景 1.2研究的意义 1.3国内外居家养老信息化管理现状分析 1.4 express框架介绍 1.5node.js功能模块 1.6论文结构与章节安排 2 居家养老服务系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1数据增加流程 2.2.2数据修改流程 2.2.…

jvm中的程序计数器、虚拟机栈和本地方法栈

引言 本文主要介绍一下jvm虚拟机中的程序计数器、虚拟机栈和本地方法栈。 程序计数器 作用 作用&#xff1a;记录下一条jvm指令的执行地址。 下面具体描述一下程序计数器的作用。 这里有两个代码&#xff0c;右边的为源代码&#xff0c;左边为编译之后的字节码。 当我们…

ElasticSearch分页查询性能及封装实现

Es的分页方式 fromsize 最基本的分页方式&#xff0c;类似于SQL中的Limit语法&#xff1a; //查询年龄在12到32之间的前15条数据 {"query":{"bool":{"must":{"range":{"user_age":{"gte":12,"lte":3…

vue实现数据栏无缝滚动实现方式-demo

效果 方式一 通过实现两个item 进行循环 <!--* Author: Jackie* Date: 2023-08-16 21:27:42* LastEditTime: 2023-08-16 21:41:51* LastEditors: Jackie* Description: scroll 水平滚动 - 效果基本满足需求* FilePath: /vue3-swiper-demo/src/components/scroll/Scroll12.…

Linux线程同步与互斥

&#x1f30e;Linux线程同步与互斥 文章目录&#xff1a; Linux线程同步与互斥 Linux线程互斥 线程锁       互斥量Mutex         初始化互斥量的两种方式         申请锁方式         解除与销毁锁 问题解决及线程饥饿       互斥锁的底…

MWD天气图像多分类数据集,用于图像分类总共6个类别,多云,下雨,下雪,雾天,正常天气,共60000张图像数据

MWD天气图像多分类数据集&#xff0c;用于图像分类 总共6个类别&#xff0c;多云&#xff0c;下雨&#xff0c;下雪&#xff0c;雾天&#xff0c;正常天气&#xff0c;共60000张图像数据 MWD天气图像多分类数据集 (Multi-Weather Dataset, MWD) 数据集描述 MWD天气图像多分类…

AcWing算法基础课-790数的三次方根-Java题解

大家好&#xff0c;我是何未来&#xff0c;本篇文章给大家讲解《AcWing算法基础课》790 题——数的三次方根。本题考查算法为浮点数二分查找。本文详细介绍了一个使用二分法计算浮点数三次方根的算法。通过逐步逼近目标值&#xff0c;程序能够在给定的区间内精确计算出结果&…

【Elasticsearch系列廿】Logstash 学习

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

什么是Rspack?

Rspack 是一个基于 Rust 编写的高性能 JavaScript 打包工具&#xff0c;旨在提供与 webpack 生态系统的强兼容性&#xff0c;允许无缝替换 webpack&#xff0c;并提供极快的构建速度。 介绍 - Rspack 它由字节跳动 Web Infra 团队孵化&#xff0c;具有以下特点&#xff1a; 高…

2024年汉字小达人区级自由报名备考冲刺:最新问题和官模题练一练

2024年第十一届汉字小达人的区级活动的时间9月25-30日正式开赛&#xff0c;还有两天就开始比赛。 今天继续回答几个关于汉字小达人的最新问题&#xff0c;做几道2024年官方模拟题&#xff0c;帮助孩子们更精准地备考2024年汉字小达人。 【温馨提示】本专题在比赛期间持续更新…

委托的注册及注销+观察者模式

事件 委托变量如果公开出去&#xff0c;很不安全&#xff0c;外部可以随意调用 所以取消public,封闭它&#xff0c;我们可以自己书写两个方法&#xff0c;供外部注册与注销&#xff0c;委托调用在子方法里调用&#xff0c;这样封装委托变量可以使它更安全&#xff0c;这个就叫…

LLM大模型训练/推理的显卡内存需求计算

无论你是从头开始训练 LLM、对其进行微调还是部署现有模型&#xff0c;选择合适的 GPU 对成本和效率都至关重要。在这篇博客中&#xff0c;我们将详细介绍使用单个和多个 GPU 以及不同的优化器和批处理大小进行 LLM 训练和推理时 GPU 要求的所有信息。 计算机处理器由多个决定…

C/C++逆向:switch语句逆向分析

在逆向分析中&#xff0c;switch语句会被编译器转化为不同的底层实现方式&#xff0c;这取决于编译器优化和具体的场景。常见的实现方式包括以下几种&#xff1a; ①顺序判断&#xff08;if-else链&#xff09;&#xff1a; 编译器将switch语句转化为一系列的if-else语句。这…