当前位置: 首页 > news >正文

java 并发编程 (2)Thread 类和 Runnable 接口详解

目录

1. Thread 类和 Runnable 接口的设计目的

1.1 为什么有 Thread 类和 Runnable 接口?

2. Thread 类实现的详细分析

2.1 Thread 类的构造方法

2.2 start() 方法的工作原理

2.3 run() 方法

2.4 join() 方法

3. Runnable 接口的实现和作用

3.1 Runnable 接口的设计目标

3.2 Runnable 的使用方式

3.3 Runnable 和 Thread 的解耦

4. Thread 和 Runnable 的优缺点比较

5. 常见的线程池与 Runnable 配合使用

5.1 使用 ExecutorService 线程池

6. 总结


1. Thread 类和 Runnable 接口的设计目的

1.1 为什么有 Thread 类和 Runnable 接口?

Thread 类和 Runnable 接口是 Java 多线程编程的核心。它们设计的目的分别是:

  • Thread:直接管理线程的生命周期和线程的运行。每个 Thread 类对象代表一个操作系统中的线程,你可以通过 start() 方法启动线程,通过 run() 方法执行任务。
  • Runnable 接口:定义线程要执行的任务。它使得任务与线程解耦,从而让同一个任务可以在多个线程中执行,提高了任务的复用性和灵活性。

2. Thread 类实现的详细分析

Thread 类是 Java 中用于创建和控制线程的主要类。它实现了 Runnable 接口,提供了线程管理和调度的基本方法。

2.1 Thread 类的构造方法

Thread 类提供了多种构造方法,但我们常用的有两种:

public Thread(Runnable target) { ... }
Runnable target:传入一个 Runnable 对象,这个对象表示线程执行的任务。Thread 会在 run() 方法中调用 Runnable 的 run() 方法。
public Thread(Runnable target, String name) { ... }
String name:给线程命名,便于调试和监控。线程的名称在大多数情况下是可选的,但在多线程调试时非常有用。
2.2 start() 方法的工作原理

start() 方法启动线程,实际的底层实现是通过操作系统的线程调度机制来启动一个新线程。我们来详细看看 Thread 类的 start() 方法:

public synchronized void start() {if (threadStatus != NEW) throw new IllegalThreadStateException();group.add(this);start0();  // native方法,调用底层操作系统的接口启动线程
}
  • synchronized:使用同步来保证线程的安全,确保一个线程只能调用一次 start() 方法。
  • start0():这是一个 native 方法,意味着它是用本地代码(通常是操作系统层面的代码)实现的。这个方法的作用是通知操作系统为当前线程分配执行资源,并启动它。
2.3 run() 方法

线程的任务是通过 run() 方法来定义的。Thread 类中有一个默认的 run() 方法:

public void run() {if (target != null) {target.run();  // 如果传入了Runnable任务,则执行它}
}
  • target 是在构造线程时传入的 Runnable 对象。run() 方法会调用 Runnable.run() 方法来执行任务。
  • 如果没有传入 Runnable 对象,那么 run() 方法什么也不做。

2.4 join() 方法

join()Thread 类的一个非常有用的方法,用于线程间的同步。通过 join(),我们可以让当前线程等待某个线程执行完毕再继续执行。

public final void join(long millis) throws InterruptedException {if (millis <= 0) {join();} else {long startTime = System.currentTimeMillis();long remainingTime = millis;synchronized (this) {while (isAlive()) {wait(remainingTime);remainingTime = millis - (System.currentTimeMillis() - startTime);if (remainingTime <= 0) break;}}}
}

join() 方法内部通过 wait()notify() 实现线程的等待机制。主线程可以通过调用其他线程的 join() 来阻塞等待该线程的执行结束。

3. Runnable 接口的实现和作用

3.1 Runnable 接口的设计目标

Runnable 是一个功能性接口,它没有线程管理的功能,只定义了线程执行的任务。它的作用是将任务与线程的管理分开。

public interface Runnable {void run();  // 线程要执行的任务
}
3.2 Runnable 的使用方式

Runnable 是 Java 中实现多线程任务的常见方式之一。当我们有多个线程需要执行同一个任务时,使用 Runnable 可以更方便地传递任务。

public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("This is a task being executed by a thread.");}
}public class Main {public static void main(String[] args) {MyRunnable task = new MyRunnable();Thread thread = new Thread(task);  // 将任务传给线程thread.start();  // 启动线程}
}
3.3 RunnableThread 的解耦

Runnable 的重要优势在于它解耦了任务和线程的关系。任务(Runnable)可以独立于线程(Thread)存在,多个线程可以共享同一个任务,这样可以复用任务代码,提高代码的灵活性和可维护性。

4. ThreadRunnable 的优缺点比较

特性ThreadRunnable 接口
继承关系继承自 Thread 类,不能继承其他类只实现 Runnable 接口,可以继承其他类
灵活性不灵活,只能继承 Thread 类,不能继承其他类灵活,可以继承其他类,支持多任务复用
任务执行方式必须重写 run() 方法来执行任务只需实现 run() 方法来定义任务
适用场景当线程和任务紧密耦合,且无需继承其他类时当任务和线程解耦时,适合用 Runnable 接口
资源共享不支持共享任务允许多个线程共享同一个 Runnable 对象

5. 常见的线程池与 Runnable 配合使用

在实际开发中,我们通常不会直接使用 Thread 类来管理线程,因为线程的创建和销毁会带来较高的性能开销。更推荐使用 线程池 来管理线程,Runnable 接口可以配合线程池执行任务。

ExecutorService 是 Java 提供的一个高效的线程池接口,它允许我们以一种更简单、优雅的方式来管理线程。

5.1 使用 ExecutorService 线程池
import java.util.concurrent.*;public class ExecutorServiceExample {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(3);  // 创建一个固定大小的线程池Runnable task1 = new Runnable() {@Overridepublic void run() {System.out.println("Task 1 is executing.");}};Runnable task2 = new Runnable() {@Overridepublic void run() {System.out.println("Task 2 is executing.");}};executorService.submit(task1);  // 提交任务到线程池executorService.submit(task2);  // 提交任务到线程池executorService.shutdown();  // 关闭线程池}
}

在上面的代码中,使用 ExecutorService 来管理线程池。我们提交了多个 Runnable 任务,线程池会自动从线程池中获取空闲线程来执行这些任务。

6. 总结

  • Thread:是最基础的线程实现方式,适用于线程和任务紧密耦合的情况。通过继承 Thread 类,可以重写 run() 方法来执行任务。
  • Runnable 接口:是更灵活的方式,适用于任务和线程分离的情况。多个线程可以共享同一个 Runnable 任务,从而提高任务复用性。
  • 线程池(ExecutorService:在实际开发中,推荐使用线程池来管理线程,避免手动创建、销毁线程带来的性能开销。

相关文章:

java 并发编程 (2)Thread 类和 Runnable 接口详解

目录 1. Thread 类和 Runnable 接口的设计目的 1.1 为什么有 Thread 类和 Runnable 接口&#xff1f; 2. Thread 类实现的详细分析 2.1 Thread 类的构造方法 2.2 start() 方法的工作原理 2.3 run() 方法 2.4 join() 方法 3. Runnable 接口的实现和作用 3.1 Runnable 接…...

人工智能之数学基础:线性代数在人工智能中的地位

本文重点 从本文开始&#xff0c;我们将开启线性代数的学习&#xff0c;在线性代数中有向量、矩阵&#xff0c;以及各种性质&#xff0c;那么这些数学知识究竟和人工智能有什么关系呢&#xff1f; 重要性 机器学习和深度学习的本质就是训练模型&#xff0c;要想训练模型需要使…...

PostgreSQL WITH 子句:提高查询效率和可读性

PostgreSQL WITH 子句:提高查询效率和可读性 PostgreSQL 是一种功能强大的开源关系数据库管理系统,它以其稳定性、可靠性和高级功能而闻名。在 PostgreSQL 中,WITH 子句(也称为公用表表达式,CTE)是一种非常有用的特性,它允许用户在一个大的查询中创建一个临时的结果集,…...

TransFormer--解码器:前馈网络层、叠加和归一组件

TransFormer--解码器&#xff1a;前馈网络层、叠加和归一组件 解码器的下一个子层是前馈网络层&#xff0c;如下图所示。 解码器的前馈网络层的工作原理与我们在编码器中学到的完全相同 叠加和归一组件 和在编码器部分学到的一样&#xff0c;叠加和归一组件连接子层的输入和输…...

2024亚太杯国际赛C题参考文章50页+完整解题思路+数据处理+最终结果

中国宠物食品行业的发展趋势与汇率情景分析&#xff1a;基于多模型的量化预测与决策分析 一 、 摘要 本文针对宠物产业及相关产业的发展分析问题&#xff0c;采用多种数学建模方法和数据 分析技术&#xff0c;构建了一系列预测和评估模型。从宠物数量预测、全球市场分析、产业 …...

Kafka 分区分配及再平衡策略深度解析与消费者事务和数据积压的简单介绍

Kafka&#xff1a;分布式消息系统的核心原理与安装部署-CSDN博客 自定义 Kafka 脚本 kf-use.sh 的解析与功能与应用示例-CSDN博客 Kafka 生产者全面解析&#xff1a;从基础原理到高级实践-CSDN博客 Kafka 生产者优化与数据处理经验-CSDN博客 Kafka 工作流程解析&#xff1a…...

useEffect、useCallback、useMemo和memo的区别

前言 在构建现代 React 应用时&#xff0c;性能优化是一个关键考虑因素。随着组件的复杂性增加&#xff0c;合理管理状态和副作用变得尤为重要。React 提供了多个工具来帮助开发者优化组件性能&#xff0c;其中最常用的包括 useEffect、useCallback、useMemo 和 React.memo。这…...

layui树形组件点击树节点后高亮的解决方案

效果显示&#xff1a; 代码 //节点高亮var nodes document.getElementsByClassName("layui-tree-txt");for (var i 0; i < nodes.length; i) {if (nodes[i].innerHTML obj.data.title){nodes[i].style.color "#006BF9";nodes[i].style.fontWeight …...

大语言模型(LLM)安全:十大风险、影响和防御措施

一、什么是大语言模型&#xff08;LLM&#xff09;安全&#xff1f; 大语言模型&#xff08;LLM&#xff09;安全侧重于保护大型语言模型免受各种威胁&#xff0c;这些威胁可能会损害其功能、完整性和所处理的数据。这涉及实施措施来保护模型本身、它使用的数据以及支持它的基…...

02 —— Webpack 修改入口和出口

概念 | webpack 中文文档 | webpack中文文档 | webpack中文网 修改入口 webpack.config.js &#xff08;放在项目根目录下&#xff09; module.exports {//entry设置入口起点的文件路径entry: ./path/to/my/entry/file.js, }; 修改出口 webpack.config.js const path r…...

Go语言进阶依赖管理

1. Go语言进阶 1.1 Goroutine package mainimport ("fmt""time" )func hello(i int) {println("hello goroutine : " fmt.Sprint(i)) }func main() {for i : 0; i < 5; i {go func(j int) { hello(j) }(i) // 启动一个新的 goroutine&…...

集成了高性能ARM Cortex-M0+处理器的一款SimpleLink 2.4 GHz无线模块-RF-BM-2340B1

蓝牙模组 - RF-BM-2340B1是基于美国TI的CC2340R5为核心设计的一款SimpleLink 2.4 GHz 无线模块。支持Bluetooth 5.3 Low Energy、Zigbee 、IEEE 802.15.4g、TI 15.4-Stack (2.4 GHz)及私有协议。集成了高性能ARM Cortex-M0处理器&#xff0c;具有512 KB Flash、32 KB超低泄漏SR…...

ffmpeg本地编译不容易发现的问题 — Error:xxxxx not found!

这里区分电脑CPU架构 本次编译是在Mac笔记本&#xff0c;M1芯片上进行&#xff01; 前面大致流程&#xff1a;分为两种&#xff08;1.仅适用&#xff0c;直接下载编译好的本地安装即可&#xff1b;2.使用并查看源码&#xff0c;自己修改编译运行&#xff09;。这里介绍的是第…...

mybatis——Mapper代理方式

一、原始DAO开发问题 Dao接口实现类方法中存在大量模板方法&#xff0c;设想能否将这些代码提取出来&#xff0c;大大减轻程序员的工作 量。 调用sqlSession的数据库操作方法需要指定statement的id&#xff0c;这里存在硬编码&#xff0c;不利于开发维护。 调用SqlSession方…...

FreeRTOS——消息队列

目录 一、概念及其作用 1.1概念 1.2特点 1.3工作原理 二、相关API 2.1创建队列 2.2任务中写队列 2.3任务中读队列 2.4中断中写队列 2.5中断中读队列 三、实现原理 3.1消息队列控制块 3.2消息队列的创建 3.3消息的发送 3.3.1任务中发送 3.3.2中断中发送 3.4消息的…...

【题解】—— LeetCode一周小结46

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结45 11.切棍子的最小成本 题目链接&#xff1a;1547. 切棍子的最…...

Java项目实战II基于微信小程序的校运会管理系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导 一、前言 在充满活力与激情的校园生活中&#xff0c;校运会不仅是…...

python里的数据结构

列表&#xff08;List&#xff09; 定义和特点&#xff1a; 列表是一种有序的可变序列&#xff0c;可包含不同类型的元素&#xff0c;如整数、字符串、列表等。可以通过索引访问和修改元素&#xff0c;索引从 0 开始。代码示例&#xff1a; my_list [1, 2, apple, [4, 5]] pr…...

[Unity Demo]从零开始制作空洞骑士Hollow Knight第二十一集:制作游戏的金钱系统吉欧Geo和初步制作HUD Canvas的额外内容

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、制作游戏的金钱系统吉欧Geo以及HUD Camera 1.制作金钱系统吉欧2.制作吉欧的脚本Geo Counter逻辑处理3.制作HUD Canvas的吉欧的UI4.在敌人的HealthManager.c…...

底层逻辑之:极大似然方法(Maximum Likelihood Estimation, MLE)

简介&#xff1a; 极大似然方法&#xff08;Maximum Likelihood Estimation, MLE&#xff09;是一种用于估计统计模型参数的方法。其核心思想是基于观测数据来寻找最可能产生这些数据的模型参数。 早在1821年&#xff0c;德国数学家高斯&#xff08;C. F. Gauss&#xff09;就…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...