Java多线程编程:实现并发处理的高效利器

Java多线程编程:实现并发处理的高效利器

作者:Stevedash

发表于:2023年8月13日 20点45分

来源:Java 多线程编程 | 菜鸟教程 (runoob.com)

​ 在计算机领域,多线程编程是一项重要的技术,可以使程序同时执行多个任务,充分利用计算资源,提高系统的性能和响应能力。Java作为一门广泛应用的编程语言,提供了丰富的多线程编程支持,使得开发人员可以轻松实现并发处理。本篇博客将向您介绍Java多线程编程的基本概念、创建线程的方式、线程同步和线程通信等内容,同时还会涉及到线程的生命周期、线程的优先级和线程的常用方法。

多线程编程的优势

​ 多线程编程在提高程序性能、资源利用率和响应速度方面具有明显的优势。通过充分利用多核处理器,可以在同一时刻处理多个任务,提高系统的整体吞吐量。此外,多线程还可以用于实现一些需要并发执行的场景,如并发请求处理、数据采集、实时计算等。

创建线程的方式

Java多线程编程有三种常见的方式来创建线程:

  1. 继承Thread类: 创建一个类继承Thread类,并重写run()方法来定义线程要执行的任务。

  2. 实现Runnable接口: 创建一个实现Runnable接口的类,并实现run()方法,然后通过Thread类的构造方法创建线程对象。

  3. 实现Callable接口: 创建一个实现Callable接口的类,并实现call()方法,可以获取线程执行后的返回值。

​ 每种方式都有其特点,选择合适的方式取决于具体需求。使用继承Thread类的方式编写简单,但由于Java不支持多重继承,可能限制了其他类的继承。而实现Runnable或Callable接口的方式可以更灵活地管理线程。


线程的生命周期

线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

下图显示了一个线程完整的生命周期。img

线程的生命周期可以分为以下几个阶段:

  1. 新建状态(New): 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
  2. 就绪状态(Runnable): 当调用线程的start()方法后,线程进入就绪状态,就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度,等待获取CPU时间片执行。
  3. 运行状态(Running): 如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
  4. 阻塞状态(Blocked): **如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。**在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
    • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
    • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
    • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
  5. 死亡状态:(Terminated): 一个运行状态的线程完成任务或者其他终止条件发生时,又或者当线程的run()方法执行完毕,线程进入终止状态。

线程的优先级

每个线程都有一个优先级,用于指示线程在竞争CPU时间片时的优先顺序。线程的优先级分为1到10,其中1为最低优先级,10为最高优先级。可以使用setPriority()方法设置线程的优先级,但并不能保证优先级高的线程一定会先执行。**默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。**具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。


线程的常用方法

Java提供了一些常用的线程方法,用于管理线程的执行和状态:
  • start(): 启动线程,使其进入就绪状态。

  • join(): 等待线程执行完毕。

  • sleep(): 使线程休眠一段时间。

  • yield(): 让出CPU时间片,让其他线程执行。

  • isAlive(): 判断线程是否还存活。

示例代码

以下是一个简单的Java程序,演示了如何创建并启动多个线程,并使用线程的优先级和常用方法:
public class MultiThreadDemo {public static void main(String[] args) {Thread thread1 = new Thread(new MyRunnable("Thread 1"));Thread thread2 = new Thread(new MyRunnable("Thread 2"));thread1.setPriority(Thread.MAX_PRIORITY);thread2.setPriority(Thread.MIN_PRIORITY);thread1.start();thread2.start();try {thread1.join(); // 等待thread1执行完毕thread2.join(); // 等待thread2执行完毕} catch (InterruptedException e) {e.printStackTrace();}System.out.println("主线程结束");}//实现Runnable接口创建线程static class MyRunnable implements Runnable {private String name;public MyRunnable(String name) {this.name = name;}//通过Callable接口和Future创建线程static class MyCallable implements Callable<Integer> {private String name;public MyCallable(String name) {this.name = name;}@Overridepublic Integer call() throws Exception{//...return Integer;}//继承Thread类创建线程  三选一static class MyThread extends Thread{private String name;public MyCallable(String name) {this.name = name;}}//必须要重写run方法@Overridepublic void run() {for (int i = 1; i <= 5; i++) {System.out.println(name + ": " + i);try {Thread.sleep(1000); // 休眠1秒} catch (InterruptedException e) {e.printStackTrace();}}}}
}

下面是Thread 方法

下表列出了Thread类的一些重要方法:

序号方法描述
1public void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
2public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
3public final void setName(String name) 改变线程名称,使之与参数 name 相同。
4public final void setPriority(int priority) 更改线程的优先级。
5public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。
6public final void join(long millisec) 等待该线程终止的时间最长为 millis 毫秒。
7public void interrupt() 中断线程。
8public final boolean isAlive() 测试线程是否处于活动状态。
上述方法是被 Thread 对象调用的,下面表格的方法是 Thread 类的静态方法。
序号方法描述
1public static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
2public static void sleep(long millisec) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
3public static boolean holdsLock(Object x) 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
4public static Thread currentThread() 返回对当前正在执行的线程对象的引用。
5public static void dumpStack() 将当前线程的堆栈跟踪打印至标准错误流。

重点了解一下SetDeamon()标记成守护线程或者用户线程

基本概念:

守护线程(Daemon Thread)是一种在后台运行的线程,它的存在不会阻止程序的终止。与之相对,用户线程(User Thread)是主要用于执行应用程序逻辑的线程,“如果所有的用户线程都执行完毕,JVM 就会退出,而不管守护线程是否还在运行。”

​ 在 Java 中,我们可以通过 setDaemon(true) 方法将一个线程设置为守护线程。**默认情况下,线程都是用户线程,不会影响程序的终止。**如果想要使用守护线程,可以在创建线程后调用 setDaemon(true) 来设置它为守护线程。


守护线程的主要作用有以下几点:

  1. 后台任务执行: 守护线程通常用于执行一些不需要持续运行的后台任务,如垃圾回收(Garbage Collection)、内存管理等。通过将这些任务放在守护线程中,可以在主要任务执行完毕后,自动进行清理等工作,提高系统的整体性能和资源利用率。
  2. 资源管理: 守护线程可以用于监控和管理一些资源,如数据库连接池、网络连接等当用户线程都结束时,守护线程可以负责关闭这些资源,防止资源泄露和浪费。
  3. 周期性任务: 守护线程还可以用于执行周期性的任务,如定时器任务。这些任务可以在“后台周期性地执行,而不影响主要业务逻辑的进行。”

PS(这很重要基本上就是守护线程的重点):守护线程在程序终止时会突然中断,因此不应该在它们的代码中进行需要确保完整性的操作。另外,守护线程不应该依赖于特定的执行顺序,因为它们的执行可能会受到系统资源调度的影响。


三种创建线程的方式对比

  1. 继承 Thread 类:

    • 创建线程的方式之一是继承 Thread 类,并重写 run 方法来定义线程的任务逻辑。
    • 优点:简单,不需要额外的类来实现接口。
    • 缺点:由于 Java 不支持多继承,因此如果已经继承了其他类,则无法再使用这种方式创建线程。
    • 示例代码:
    class MyThread extends Thread {public void run() {// 线程执行的任务逻辑}
    }public class ThreadExample {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
    }
    
  2. 实现 Runnable 接口:

    • 另一种创建线程的方式是实现 Runnable 接口,并将实现类的实例传递给 Thread 类的构造函数。
    • 优点:可以避免继承单一父类的限制,同时更灵活,可以实现多个接口。
    • 缺点:相对于继承 Thread 类,需要额外的类来实现接口。
    • 示例代码:
    class MyRunnable implements Runnable {public void run() {// 线程执行的任务逻辑}
    }public class RunnableExample {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();}
    }
    
  3. 使用 CallableFuture

    • 使用 Callable 接口可以创建一个带有返回结果的任务。Future 接口可以用于获取任务的执行结果。
    • 优点:可以获取任务的返回结果,能够捕获任务抛出的异常。
    • 示例代码:
    import java.util.concurrent.*;class MyCallable implements Callable<Integer> {public Integer call() throws Exception {// 线程执行的任务逻辑return 42;}
    }public class CallableExample {public static void main(String[] args) {ExecutorService executor = Executors.newSingleThreadExecutor();Future<Integer> future = executor.submit(new MyCallable());try {int result = future.get();System.out.println("任务执行结果:" + result);} catch (Exception e) {e.printStackTrace();} finally {executor.shutdown();}}
    }
    

三种创建线程方式对比小结:

  1. 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
  2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
  3. 继承 Thread 类和实现 Runnable 接口是最基本的方式,而使用 CallableFuture 可以获得更多的控制和返回结果的能力。

线程的几个主要概念

在多线程编程时,你需要了解以下几个概念:

  • 线程同步
  • 线程间通信
  • 线程死锁
  • 线程控制:挂起、停止和恢复

注意事项和进阶功能

  • 多线程编程需要注意线程安全性和资源竞争问题,合理使用同步机制来保证数据的一致性。

  • Java提供了线程池、并发集合等工具类来简化多线程编程,提高效率和性能。

  • 在处理复杂场景时,可以使用Executor框架、Future接口等实现更高级的线程管理和任务调度。


总结

​ Java多线程编程是实现并发处理的有效手段,可以提高程序性能和响应能力。通过学习线程创建方式、线程同步、线程通信、线程的生命周期、线程的优先级和线程的常用方法,我们可以在应用程序中合理使用多线程来实现并发任务。

作者:Stevedash

发表于:2023年8月13日 20点45分

来源:Java 多线程编程 | 菜鸟教程 (runoob.com)

注:本文内容基于个人学习理解,如有错误或疏漏,欢迎指正。感谢阅读!如果觉得有帮助,请点赞和分享。

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

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

相关文章

从小白到大神之路之学习运维第79天-------Kubernetes网络组件详解

第四阶段 时 间&#xff1a;2023年8月14日 参加人&#xff1a;全班人员 内 容&#xff1a; Kubernetes网络组件详解 目录 一、Kubernetes网络组件 &#xff08;一&#xff09;Flannel网络组件 &#xff08;二&#xff09;Calico 网络插件 &#xff08;1&#xff09;…

设计模式——建造者(Builder)模式

建造者模式&#xff08;Builder Pattern&#xff09;&#xff0c;又叫生成器模式&#xff0c;是一种对象构建模式 它可以将复杂对象的建造过程抽象出来&#xff0c;使这个抽象过程的不同实现方法可以构造出不同表现的对象。建造者模式是一步一步创建一个复杂的对象&#xff0c;…

在单元测试中使用Jest模拟VS Code extension API

对VS Code extension进行单元测试时通常会遇到一个问题&#xff0c;代码中所使用的VS Code编辑器的功能都依赖于vscode库&#xff0c;但是我们在单元测试中并没有添加对vscode库的依赖&#xff0c;所以导致运行单元测试时出错。由于vscode库是作为第三方依赖被引入到我们的VS C…

[oneAPI] BERT

[oneAPI] BERT BERT训练过程Masked Language Model&#xff08;MLM&#xff09;Next Sentence Prediction&#xff08;NSP&#xff09;微调 总结基于oneAPI代码 比赛&#xff1a;https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517 Intel DevCloud for oneAPI&…

React源码解析18(4)------ completeWork的工作流程【mount】

摘要 经过上一章&#xff0c;我们得到的FilberNode已经具有了child和return属性。一颗Filber树的结构已经展现出来了。 那我们最终是想在页面渲染真实的DOM。所以我们现在要在completeWork里&#xff0c;构建出一颗离屏的DOM树。 之前在说FilberNode的属性时&#xff0c;我们…

zabbix案例--zabbix监控Tomcat

目录 一、 部署tomcat 二、配置zabbix-java-gateway 三、配置zabbix-server 四、配置zabbix-web界面 一、 部署tomcat tar xf apache-tomcat-8.5.16.tar.gz -C /usr/local/ ln -sv /usr/local/apache-tomcat-8.5.16/ /usr/local/tomcat cd /usr/local/tomcat/bin开启JMX…

Vscode 常用操作教程

一、语言换成中文 这是我们可以直接点击左边栏第四个图标搜索插件 chinese ,也可以直接ctrlshiftp快捷键也会出来如图所示图标&#xff0c;出来chinese 插件之后选择安装install,安装完成之后重新ctrlshiftp会出现如图所示页面 找到我的鼠标在的地方对应的中文&#xff0c;此时…

win10下如何安装ffmpeg

安装ffmpeg之前先安装win10 绿色软件管理软件&#xff1a;scoop. Scoop的基本介绍 Scoop是一款适用于Windows平台的命令行软件&#xff08;包&#xff09;管理工具&#xff0c;这里是Github介绍页。简单来说&#xff0c;就是可以通过命令行工具&#xff08;PowerShell、CMD等…

VVIC-商品详情

一、接口参数说明&#xff1a; item_get-根据ID取商品详情&#xff0c;点击更多API调试&#xff0c;请移步注册API账号点击获取测试key和secret 公共参数 请求地址: https://api-gw.onebound.cn/vvic/item_get 名称类型必须描述keyString是调用key&#xff08;点击获取测试k…

【MongoDB】索引

目录 一、概述 二、索引的类型 1、单字段索引 2、复合索引 3、其他索引 三、索引的管理 1、索引的创建 2、索引的查看 3、索引的删除 四、索引的使用 1、执行计划 2、涵盖的查询 一、概述 索引支持在MongoDB中高效地执行查询。如果没有索引&#xff0c;MongoDB必须…

Kubernetes pod调度约束[亲和性 污点] 生命阶段 排障手段

调度约束 Kubernetes 是通过 List-Watch 的机制进行每个组件的协作&#xff0c;保持数据同步的&#xff0c;每个组件之间的设计实现了解耦。 用户是通过 kubectl 根据配置文件&#xff0c;向 APIServer 发送命令&#xff0c;在 Node 节点上面建立 Pod 和 Container。 APIServer…

springcloud3 hystrix实现服务降级,熔断,限流以及案例配置

一 hystrix的作用 1.1 降级&#xff0c;熔断&#xff0c;限流 1.服务降级&#xff1a; A方案出现问题&#xff0c;切换到兜底方案B&#xff1b; 2.服务熔断&#xff1a;触发规则&#xff0c;出现断电限闸&#xff0c;服务降级 3.服务限流&#xff1a;限制请求数量。 二 案例…

FPGA学习——驱动WS2812光源并进行动态显示

文章目录 一、WS2812手册分析1.1 WS2812灯源特性及概述1.2 手册重点内容分析1.2.1 产品概述1.2.2 码型及24bit数据设计 二、系统设计2.1 模块设计2.2 模块分析2.2.1 驱动模块2.2.1 数据控制模块 三、IP核设置及项目源码3.1 MIF文件设计3.2 ROM IP核调用3.3 FIFO IP核调用3.4 项…

源码断点分析Spring的占位符(Placeholder)是怎么工作的

项目中经常需要使用到占位符来满足多环境不同配置信息的需求&#xff0c;比如&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns"http://www.springframe…

【爱书不爱输的程序猿】CPOLAR+HFS,低成本搭建NAS

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 通过HFS低成本搭建NAS&#xff0c;并内网穿透实现公网访问 - cpolar 极点云 前言1.下载安装cpolar1.1 设置HFS访客1.2 虚拟文件系统 2. 使用cpolar建立一条内网穿透数据隧道2.1 保留…

(三) 搞定SOME/IP通信之CommonAPI库

本章主要介绍在SOME/IP通信过程中的另外一个IPC通信利剑,CommonAPI库,文章将从如下几个角度让读者了解什么是CommonAPI, 以及库在实际工作中的作用 SOME/IP通信之CommonAPI CommonAPI库是什么CommonAPI库的编译写个Demo实战一下CommonAPI库是什么 CommonAPI是GENIVI组织开发…

推出 Elasticsearch 查询语言 (ES|QL)

作者&#xff1a;Costin Leau 我很高兴地宣布&#xff0c;经过大约一年的开发&#xff0c;Elasticsearch 查询语言 (ES|QL) 已准备好与世界共享&#xff0c;并已登陆 Elasticsearch 存储库。 ES|QL 是 Elasticsearch 原生的强大声明性语言&#xff0c;专为可组合性、表现力和速…

Django-配置邮箱功能(一):使用django自带的发送邮件功能

一、获取邮箱授权码 以QQ邮箱为例子&#xff1a; 1、进入到设置&#xff0c;找到账户 2、开启POP3等服务&#xff0c;点击管理服务 3、进入管理服务&#xff0c;生成授权码 4、按照要求发送短信就可以了 5、将授权码复制保存&#xff0c;离开界面就看不到了 二、django项目中…

2023上半年京东手机行业品牌销售排行榜(京东数据平台)

后疫情时代&#xff0c;不少行业都迎来消费复苏&#xff0c;我国智能手机市场在今年上半年也实现温和的复苏&#xff0c;手机市场的出货量回暖。 根据鲸参谋平台的数据显示&#xff0c;2023年上半年&#xff0c;京东平台上手机的销量为2830万&#xff0c;环比增长约4%&#xf…

引入三阶失真的非线性放大器的模拟输出及使用中值滤波器去除峰值研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…