多线程的创建方式以及及Thread类详解

目录

一.线程的创建方法:(重点)

        一:继承Thread类

写法一:正常写法

写法二:匿名内部类 

二.实现Runnable接口 

写法一:正常写法

 写法二:匿名内部类 

三. 实现 Callable 接口 

​编辑

四.通过线程池创建线程

二.Thread类及常⻅⽅法

1.Thread的常⻅构造⽅法

2.Thread的⼏个常⻅属性

3.Thread常见方法(重点)

run()方法 和start()方法(区别)

join()方法

 中断线程

sleep()方法 


一.线程的创建方法:(重点)

        一:继承Thread类

写法一:正常写法

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务

  2. 创建Thread子类的实例,即创建了线程对象

  3. 调用线程对象的start()方法来启动该线程

public class MyThread  extends  Thread{@Overridepublic void run() {while (true) {System.out.println("这里是子线程");}}public static void main(String[] args) {MyThread thread1 = new MyThread();thread1.start();while (true) {System.out.println("这里是主线程");}}
}

 

写法二:匿名内部类 

    public static void main(String[] args) {Thread thread = new Thread() {@Overridepublic void run() {while (true) {System.out.println("这里是thread线程");}}};thread.start();while (true) {System.out.println("这里是main线程");}}


二.实现Runnable接口 

写法一:正常写法

  1. 创建一个实现了Runnable接口的类,并实现接口中的run()方法,定义线程的执行逻辑。
  2. 在主线程中创建Runnable实例,并将其作为参数传递给Thread类的构造方法。
  3. 调用Thread对象的start()方法启动线程。
public class MyRunnable implements Runnable{@Overridepublic void run() {while (true) {System.out.println("thread!");}}public static void main(String[] args) {MyRunnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start();while (true) {System.out.println("main!");}}
}

 

 写法二:匿名内部类 

    public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while (true) {System.out.println("thread!");}}});thread.start();while (true) {System.out.println("main!");}}

三. 实现 Callable 接口 

前两种方式都存在一个问题:重写的run方法均不能直接返回结果,不适合需要返回线程执行结果的场景。而通过实现Callable接口则可以做到这一点。

  1. 得到任务对象定义类实现Callable接口,重写call方法,封装要做的事情,用FutureTask把Callable对象封装成线程任务对象
  2. 把线程任务对象交给Thread处理
  3. 调用Thread的start方法启动线程,执行任务
  4. 线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果
public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {for (int i = 0; i < 3; i++) {System.out.println("thread:" + i);}return "call!";}public static void main(String[] args) throws ExecutionException, InterruptedException {MyCallable myCallable = new MyCallable();FutureTask<String> futureTask = new FutureTask<>(myCallable);Thread thread = new Thread(futureTask);thread.start();for (int i = 0; i < 3; i++) {System.out.println("main:"+i);}System.out.println(futureTask.get());}
}


四.通过线程池创建线程

后序再详讲


二.Thread类及常⻅⽅法

1.Thread的常⻅构造⽅法

  • Thread t1 = new Thread();
  • Thread t2 = new Thread(new MyRunnable());
  • Thread t3 = new Thread("这是我的名字");
  • Thread t4 = new Thread(new MyRunnable(), "这是我的名字");

2.Thread的⼏个常⻅属性

  •  ID是线程的唯⼀标识,不同线程不会重复
  • 名称是各种调试⼯具⽤到
  •  状态表⽰线程当前所处的⼀个情况,下⾯我们会进⼀步说明
  •  优先级⾼的线程理论上来说更容易被调度到
  •  关于后台线程,需要记住⼀点:JVM会在⼀个进程的所有⾮后台线程结束后,才会结束运⾏。
  • 是否存活,即简单的理解,为run⽅法是否运⾏结束了
  • 线程的中断问题,下⾯我们进⼀步说明 

3.Thread常见方法(重点)

run()方法 和start()方法(区别)

  • start()方法是Thread类中的一个方法,用于启动一个新的线程。当调用start()方法时,系统会创建一个新的线程,并在新的线程中执行run()方法的内容。start()方法会在新的线程中执行一些准备工作,然后调用run()方法。
  • run()方法是实现了Runnable接口的类中的一个方法。在启动一个线程后,系统会自动调用该线程对象的run()方法。run()方法中包含了线程的主体代码,即线程要执行的任务。

2.start()方法

public class MyThread extends Thread{@Overridepublic void run() {while (true) {System.out.println("这里是thread");}}public static void main(String[] args) {MyThread thread = new MyThread() ;thread.start();while (true) {System.out.println("这里是main线程");}}
}

此时为俩个线程并发处理

1.run()方法

 public class MyThread extends Thread{@Overridepublic void run() {while (true) {System.out.println("这里是thread");}}public static void main(String[] args) {MyThread thread = new MyThread() ;thread.run();while (true) {System.out.println("这里是main线程");}}
}

此时只实现了run方法 并没有并发处理 

总结:

  • start() 方法 用于启动一个新线程,它会触发线程的创建和调度,最终由操作系统负责执行 run() 方法。
  • run() 方法 是线程的实际执行任务,是线程执行的代码部分。如果直接调用 run() 方法,它会在当前线程中执行,并不会启动新的线程。

join()方法

在多个线程中,他们的执行顺序属于系统调动的,是无序的(抢占式执行)

而我们希望一个稳定的顺序,如何执行?

join() 方法的使用场景:

场景 1:确保多个线程按顺序执行

有时,你可能希望在主线程中启动多个子线程,并确保在继续执行后续任务之前,所有子线程已经完成。例如,在处理多个任务并且它们之间有依赖关系时,必须等待所有线程完成。

场景 2:等待线程完成后汇总结果

在多线程并发计算时,主线程可能需要等待多个线程完成任务,才能进行汇总或处理结果。join() 方法可以帮助你等待所有线程执行完成后再进行下一步操作。

场景 3:避免主线程提前退出

如果没有使用 join(),主线程可能会在子线程完成之前就退出,导致子线程未执行完成。使用 join() 可以保证主线程在所有子线程完成之前不会退出。

 

案例:

class MyThread extends Thread {private String name;public MyThread(String name) {this.name = name;}public void run() {System.out.println(name + " 正在执行...");try {Thread.sleep(1000); // 模拟任务执行} catch (InterruptedException e) {e.printStackTrace();}System.out.println(name + " 执行完毕!");}
}public class Main {public static void main(String[] args) throws InterruptedException {MyThread thread1 = new MyThread("线程1");MyThread thread2 = new MyThread("线程2");MyThread thread3 = new MyThread("线程3");thread1.start();thread2.start();thread3.start();// 主线程等待所有子线程执行完毕thread1.join();thread2.join();thread3.join();System.out.println("所有线程都已执行完毕,主线程继续执行...");}
}

  • 在这个例子中,主线程通过调用 thread1.join()thread2.join() 和 thread3.join() 来等待所有子线程执行完毕。
  • 主线程会阻塞,直到 thread1thread2 和 thread3 执行完成。
  • 当所有线程执行完毕后,主线程输出 "所有线程都已执行完毕,主线程继续执行..."

总结:

  1. 确保线程顺序:有时我们希望线程按照特定的顺序执行。使用 join() 可以让主线程等待子线程执行完毕,这样就能保证主线程在子线程之后才继续执行。

  2. 避免主线程提前退出:在多线程应用中,如果主线程没有等待子线程完成就退出,可能导致子线程未完成时程序就结束了,特别是在没有使用 join() 时,主线程可能比子线程先结束。

  3. 汇总线程结果:如果多个线程在并行执行,主线程可能需要等待它们执行完毕后再进行结果汇总。join() 方法能够确保线程完成后,主线程能够获取到所有线程的执行结果。

  4. 避免线程竞态条件:通过确保线程按顺序执行,join() 可以避免一些可能的竞态条件和线程同步问题。


 中断线程

在 Java 多线程编程中,中断线程是一种用于请求线程停止执行的机制。线程的中断并不意味着直接停止线程的执行,而是给线程发送一个中断信号,让线程有机会在合适的地方处理这个信号并终止。线程中断通常用于协调多个线程的生命周期,特别是在需要停止一个线程的执行时,或者是某个线程的操作不再需要时

线程中断的使用场景:

  1. 停止正在执行的线程: 当线程正在进行耗时的任务时,如果你需要在某个时刻停止它,可以通过中断来实现。中断信号告诉线程它可以停止工作或清理资源并退出。

    应用场景:比如有一个后台线程在执行某些长时间的计算任务或下载操作,如果用户取消了操作,你可以通过中断线程来停止这些任务。

  2. 响应外部中断请求: 比如在一个多线程的客户端应用中,如果用户要求退出程序或者停止某些操作,可以通过发送中断信号来优雅地停止正在运行的线程。

    应用场景:比如在一个多线程的 HTTP 请求处理系统中,如果服务器需要停止处理请求,可以通过中断正在处理请求的线程。

  3. 在阻塞操作中响应中断: 当线程执行如 sleep()join()wait() 等阻塞操作时,可以中断线程来提前终止阻塞操作,从而使线程能够继续执行其他任务。

    应用场景:在多线程的网络编程中,可能需要等待其他线程的响应,如果等待超时,则可以通过中断等待线程,防止程序长时间处于等待状态。

  4. 取消正在执行的任务: 在一些任务执行框架中,可以通过中断来取消正在执行的任务。当任务执行时间过长,或者任务本身不再需要时,可以通过中断来提示线程终止。

    应用场景:比如在处理大量数据时,当用户主动取消任务时,可以中断相关的线程。

 案例1:使用 Thread.interrupt() 中断线程

public class InterruptExample {public static void main(String[] args) {// 创建线程Thread thread = new Thread(() -> {try {System.out.println("线程开始执行");// 模拟一个长时间的任务for (int i = 0; i < 10; i++) {if (Thread.currentThread().isInterrupted()) {System.out.println("线程被中断,退出循环");return;}Thread.sleep(1000);  // 模拟工作System.out.println("线程正在工作,执行第 " + (i + 1) + " 次");}} catch (InterruptedException e) {System.out.println("线程在阻塞时被中断:" + e.getMessage());}});thread.start();try {// 等待一会儿,然后中断线程Thread.sleep(3000);thread.interrupt();  // 请求中断线程} catch (InterruptedException e) {e.printStackTrace();}}
}

示例 2:线程阻塞时的中断 

public class InterruptInSleepExample {public static void main(String[] args) {Thread thread = new Thread(() -> {try {System.out.println("线程开始执行,准备休眠");Thread.sleep(5000);  // 模拟长时间的阻塞操作System.out.println("线程正常执行完毕");} catch (InterruptedException e) {System.out.println("线程被中断,异常信息:" + e.getMessage());}});thread.start();try {// 等待 2 秒钟然后中断线程Thread.sleep(2000);thread.interrupt();  // 请求中断线程} catch (InterruptedException e) {e.printStackTrace();}}
}

总结

  • 中断线程是通过 Thread.interrupt() 方法发出请求,线程可以通过检查中断状态来响应这个请求。
  • 常见的使用场景包括:停止长时间运行的任务、在阻塞操作中响应外部请求、取消正在进行的操作等。
  • 线程中断是一种“协作式的停止”,即线程需要在合适的地方主动检查中断状态并退出。

sleep()方法 

在Java中,sleep() 方法是 Thread 类中的一个静态方法,用于暂停当前执行的线程指定的时间

案例:定时打印信息

public class TimerTaskExample {public static void main(String[] args) {Long start = System.currentTimeMillis();for (int i = 1; i <= 5; i++) {System.out.println("第 " + i + " 次执行");try {// 每次执行后休眠1秒Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}Long end = System.currentTimeMillis();System.out.println("总共耗时:"+(end-start));}
}


结语: 写博客不仅仅是为了分享学习经历,同时这也有利于我巩固知识点,总结该知识点,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进。同时也希望读者们不吝啬你们的点赞+收藏+关注,你们的鼓励是我创作的最大动力! 

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

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

相关文章

408最后冲刺阶段,怎么做题才能考到120+?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 重要性排序如下&#xff1a;真题占据首位&#xff0c;紧随其后的是王道模拟题&#xff0c;王道书与题目则紧随其后&#xff0c;而408统考配套习题&#xff08;高教版&#xff09;与之大致相当。 真题&#xff0c;无疑…

如何对接低价又稳定的影视会员渠道?

对接低价折扣影视会员渠道通常涉及到与影视内容提供商或第三方分销商的合作。以下是一些基本步骤和注意事项&#xff0c;帮助你顺利对接这类渠道&#xff1a; 1. 市场调研 了解市场&#xff1a;研究市场上现有的影视会员服务提供商&#xff0c;包括价格、服务、用户反馈等。确…

crond 任务调度 (Linux相关指令:crontab)

相关视频链接 crontab 进行 定时任务 的设置 概述 任务调度&#xff1a;是指系统在某个时间执行的特定的命令或程序 任务调度的分类&#xff1a; 1.系统工作&#xff1a;有些重要的工作必须周而复始地执行。如病毒扫描等。 2.个别用户可能希望执行某些程序&#xff0c;比如…

顺序表+ArrayList

文章目录 一、基础知识1.1 数据结构类的继承图1.2 List 介绍1.3 线性表 二、数据结构 -- 顺序表2.1 什么是顺序表以及优缺点2.2 用数组实现顺序表细节解析代码 三、ArrayList3.1 Java中如何使用ArrayList3.2 ArrayList源码无参构造方法add方法扩容方法指定初始容量构造利用其他…

【工具变量】排污权交易政策试点DID(2000-2023)

数据简介&#xff1a;在过去几十年间的“高增长、高能耗、高污染”的经济发展背景下&#xff0c;随着社会各界不断反应高经济增长背后付出的巨大环境代价&#xff0c;中国ZF将节能环保减排纳入长期规划治理中。在2007年&#xff0c;我国开始启动了二氧化硫&#xff08;SO2&…

通用特效Shader

一、通用特效Shader介绍 1.1 什么是通用特效材质 Unity支持SRP Batcher后&#xff0c;使用UberShader的优势非常明显。所谓&#xff0c;UberShader&#xff0c;即一个超级Shader&#xff0c;覆盖一类功能&#xff0c;而不是多个分散的小Shader&#xff0c;比如一个通用特效Sh…

网络安全SQL初步注入2

六.报错注入 mysql函数 updatexml(1,xpath语法,0) xpath语法常用concat拼接 例如: concat(07e,(查询语句),07e) select table_name from information_schema.tables limit 0,1 七.宽字节注入(如果后台数据库的编码为GBK) url编码:为了防止提交的数据和url中的一些有特殊意…

Golang--面向对象

Golang语言面向对象编程说明&#xff1a; Golang也支持面向对象编程(OOP)&#xff0c;但是和传统的面向对象编程有区别&#xff0c;并不是纯粹的面向对象语言。所以我们说Golang支持面向对象编程特性是比较准确的。Golang没有类(class)&#xff0c;Go语言的结构体(struct)和其…

英国留学论文写作中复合句式基础知识讲解

从句子的结构出发&#xff0c;复合句式是将两个以上的独立、完整的字句子通过coordinating conjunction或者分号连接在一起。因此&#xff0c;复合句式可以理解成为两个以上的简单句子组合在一起。下面英国翰思教育通过举例的方式&#xff0c;来介绍如何将独立的句子连接在一起…

从奇富科技,QQ钱包看信贷服务、贷款超市的的客户注册认证流程有什么不同

概览 奇富科技作为港股信贷第一企业&#xff0c;目前已服务2.4亿用户&#xff0c;是国内头部信贷科技服务平台。 QQ钱包&#xff0c;作为8亿用户的贷款超市&#xff0c;拥有其他贷款超市产品梦寐以求的流量入口。 产品模式 奇富科技作为信贷科技服务平台&#xff0c;主要提…

寻找伤感短视频素材 这些网站帮你轻松下载无水印资源

无论是制作情感类短视频&#xff0c;还是为抖音视频寻找合适的素材&#xff0c;伤感视频素材一直是创作者们关注的重点。如果你正在为如何找到高质量的伤感素材而困扰&#xff0c;那么今天我将推荐一些非常实用的素材网站&#xff0c;帮助你快速找到适合的伤感视频素材&#xf…

Java项目实战II基于Spring Boot的大学生智能消费记账系统的设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在当今社会…

Linux 抓包工具 --- tcpdump

序言 在传输层 Tcp 的学习中&#xff0c;我们了解了 三次握手和四次挥手 的概念&#xff0c;但是看了这么多篇文章&#xff0c;我们也只是停留在 纸上谈兵。  欲知事情如何&#xff0c;我们其实可以尝试去看一下具体的网络包的信息。在这篇文章中将向大家介绍&#xff0c;在 L…

基于Spring Boot+Vue的养老院管理系统【原创】

一.系统开发工具与环境搭建 1.系统设计开发工具 后端使用Java编程语言的Spring boot框架 项目架构&#xff1a;B/S架构 运行环境&#xff1a;win10/win11、jdk17 前端&#xff1a; 技术&#xff1a;框架Vue.js&#xff1b;UI库&#xff1a;ElementUI&#xff1b; 开发工具&…

基于SpringBoot+Vue音乐播放和推荐系统【提供源码+答辩PPT+参考文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

震撼!通过双重异步,Excel 10万行数据导入从191秒优化到2秒!

震撼&#xff01;通过双重异步&#xff0c;Excel 10万行数据导入从191秒优化到2秒&#xff01; 在现代的企业级应用开发中&#xff0c;海量数据的处理效率和并发性能优化是一个非常重要的课题。无论是大规模数据导入、文件解析&#xff0c;还是在分布式系统中处理高并发任务&a…

Linux编程:用于调试 C、C++ 和其他编程语言编写的程序的调试工具GDB的使用

目录 一、概述 二、 安装GDB 三、准备程序 四、使用GDB 1、启动GDB 2、获取帮助 五、 常用GDB命令 六、示例调试会话 七、其他事项 一、概述 GDB&#xff08;GNU Debugger&#xff09;是一个非常强大的调试工具&#xff0c;广泛用于调试 C、C 和其他编程语言编写的程序…

书生实战营第四期-基础岛第五关-XTuner 微调个人小助手认知

基础任务 使用 XTuner 微调 InternLM2-Chat-7B 实现自己的小助手认知 一、环境配置与数据准备 1.构建虚拟环境 cd ~ #git clone 本repo git clone https://github.com/InternLM/Tutorial.git -b camp4 mkdir -p /root/finetune && cd /root/finetune conda create -…

java day04-面向对象基础(内存 封装 继承 修饰符 工具类 )

1.对象内存图 1.1 Java 内存分配 1.2 堆和栈 栈:所有局部变量都会在栈内存中创建 局部变量&#xff1a;定义在方法中的变量或者方法声明上的变量 方法执行都会加载到栈中进行 -----------------------------------------------------------------------------------------…

【C++练习】二进制到十进制的转换器

题目&#xff1a;二进制到十进制的转换器 描述 编写一个程序&#xff0c;将用户输入的8位二进制数转换成对应的十进制数并输出。如果用户输入的二进制数不是8位&#xff0c;则程序应提示用户输入无效&#xff0c;并终止运行。 要求 程序应首先提示用户输入一个8位二进制数。…