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

深入理解 Java 多线程:原理剖析与实战指南

深入理解 Java 多线程:原理剖析与实战指南

一、引言

在现代软件开发中,多线程编程已经成为提升应用性能与响应能力的重要手段。Java 作为一门成熟的编程语言,自 JDK 1.0 起就提供了对多线程的原生支持。本文将深入剖析 Java 多线程的底层原理,并结合实际开发场景,系统讲解如何合理、安全地使用多线程技术。


二、Java 多线程基础原理

1. 什么是线程?

线程是操作系统能够进行运算调度的最小单位。一个进程可以包含多个线程,多个线程共享进程的资源但拥有各自的执行路径和栈空间。

2. Java 中的线程模型

Java 使用 java.lang.Threadjava.lang.Runnable 接口作为基本的多线程实现方式,从 JDK 1.5 之后又引入了 Executor 框架,极大地简化了线程管理。


三、Java 创建线程的四种方式

1. 继承 Thread 类

public class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行");}public static void main(String[] args) {MyThread t1 = new MyThread();t1.start(); // 启动线程,调用 run 方法}
}

2. 实现 Runnable 接口

public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行");}public static void main(String[] args) {Thread t1 = new Thread(new MyRunnable());t1.start();}
}

3. 使用 Callable 和 Future

import java.util.concurrent.*;public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "线程执行完成,结果为:" + Thread.currentThread().getName();}public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executor = Executors.newSingleThreadExecutor();Future<String> future = executor.submit(new MyCallable());System.out.println(future.get()); // 阻塞等待返回结果executor.shutdown();}
}

4. 使用线程池(推荐)

import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(3);for (int i = 0; i < 5; i++) {final int taskId = i;executor.execute(() -> {System.out.println("任务 " + taskId + " 由线程 " + Thread.currentThread().getName() + " 执行");});}executor.shutdown();}
}

四、线程调度与状态转换

Java 中线程的状态(👉深入解析Java线程状态与生命周期)包括:

  • NEW(新建)
  • RUNNABLE(运行)
  • BLOCKED(阻塞)
  • WAITING / TIMED_WAITING(等待)
  • TERMINATED(终止)

状态转换由 start(), sleep(), wait(), notify() 等方法控制(👉深入理解Java多线程编程中的常用方法及应用),底层依赖 JVM 的线程调度器(操作系统的调度策略)。


五、线程同步机制详解

1. synchronized(👉深入解析 Java 中的 Synchronized:原理、实现与性能优化) 关键字

public class SynchronizedExample {private int count = 0;public synchronized void increment() {count++;}public static void main(String[] args) throws InterruptedException {SynchronizedExample example = new SynchronizedExample();Thread t1 = new Thread(() -> {for (int i = 0; i < 10000; i++) example.increment();});Thread t2 = new Thread(() -> {for (int i = 0; i < 10000; i++) example.increment();});t1.start(); t2.start();t1.join(); t2.join();System.out.println("最终 count 值为:" + example.count);}
}

2. 使用 Lock 接口

import java.util.concurrent.locks.ReentrantLock;public class LockExample {private final ReentrantLock lock = new ReentrantLock();private int count = 0;public void increment() {lock.lock();try {count++;} finally {lock.unlock();}}
}

六、可见性与原子性:volatile (👉深入理解java中的volatile关键字)和原子类

1. volatile 保证可见性但不保证原子性

public class VolatileExample {private volatile boolean running = true;public void stop() {running = false;}public void start() {while (running) {// do something}}
}

2. 原子类的使用

import java.util.concurrent.atomic.AtomicInteger;public class AtomicExample {private AtomicInteger count = new AtomicInteger(0);public void increment() {count.incrementAndGet(); // 原子操作}
}

七、线程通信:wait / notify 机制

public class WaitNotifyExample {private static final Object lock = new Object();private static boolean ready = false;public static void main(String[] args) {Thread producer = new Thread(() -> {synchronized (lock) {ready = true;lock.notify(); // 通知消费者System.out.println("生产者:已通知");}});Thread consumer = new Thread(() -> {synchronized (lock) {while (!ready) {try {lock.wait(); // 等待通知} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("消费者:收到通知");}});consumer.start();try { Thread.sleep(100); } catch (InterruptedException ignored) {}producer.start();}
}

八、Executor 框架实战案例:并发网页爬取器

import java.util.concurrent.*;public class WebCrawler {private final ExecutorService executor = Executors.newFixedThreadPool(5);public void crawl(String[] urls) {for (String url : urls) {executor.submit(() -> {System.out.println("爬取:" + url + " by " + Thread.currentThread().getName());// 模拟网络请求try { Thread.sleep(100); } catch (InterruptedException ignored) {}});}}public void shutdown() {executor.shutdown();}public static void main(String[] args) {WebCrawler crawler = new WebCrawler();String[] urls = {"http://example.com/1", "http://example.com/2", "http://example.com/3"};crawler.crawl(urls);crawler.shutdown();}
}

自定义线程池可参考👉java中自定义线程池最佳实践

九、避免死锁的几种策略

  1. 保持锁的获取顺序一致。
  2. 尽量减少锁的持有时间。
  3. 使用 tryLock()(👉全面详解Java并发编程:从基础到高级应用) 设置超时。
  4. 使用高级并发工具如 Semaphore(👉Java 并发编程之AQS), ConcurrentHashMap(👉全面解读ConcurrentHashMap:Java中的高效并发数据结构), BlockingQueue(👉Java 线程池原理详解) 等。

十、总结

Java 多线程是一项强大而复杂的工具。理解其核心机制——线程创建、同步、通信与调度——是构建高性能、可扩展程序的关键。本文通过理论讲解与实际代码结合,帮助你在开发中更安全、有效地运用多线程技术。


相关文章:

深入理解 Java 多线程:原理剖析与实战指南

深入理解 Java 多线程&#xff1a;原理剖析与实战指南 一、引言 在现代软件开发中&#xff0c;多线程编程已经成为提升应用性能与响应能力的重要手段。Java 作为一门成熟的编程语言&#xff0c;自 JDK 1.0 起就提供了对多线程的原生支持。本文将深入剖析 Java 多线程的底层原…...

Qt/C++学习系列之Excel使用记录

Qt/C学习系列之Excel使用记录 前言The process was ended forcefully.解决方式断点查语句问题 总结 前言 在项目中解析条目达50多条&#xff0c;并且都需要将对应的结果进行显示。为了将结果显示的更加清晰&#xff0c;考虑采用QTableWidget进行表格设置&#xff0c;而在使用过…...

跳转指令四维全解:从【call/jmp 】的时空法则到内存迷宫导航术

一、核心概念&#xff1a;代码世界的空间定位法则 在汇编世界里&#xff0c;我们可以把内存想象成一栋巨大的图书馆&#xff1a; CS&#xff08;代码段寄存器&#xff09; 楼层编号 IP&#xff08;指令指针&#xff09; 房间编号 当前执行位置 CS:IP&#xff08;如3楼201…...

LabVIEW实时系统数据监控与本地存储

基于LabVIEW Real-Time 模块&#xff0c;面向工业自动化、嵌入式测控等场景&#xff0c;提供实时数据采集、监控与本地存储的完整实现路径。通过分层任务调度、TDMS 文件格式应用及跨平台兼容性设计&#xff0c;确保系统在实时性、可靠性与数据管理效率间达到平衡。文中以 Comp…...

从 Revit 到 3DTiles:GISBox RVT 切片器如何让建筑图元在 Web 端展示

在GIS&#xff08;地理信息系统&#xff09;行业蓬勃发展的当下&#xff0c;数据处理与展示的效率和精准度成为关键。GISBox作为一款功能强大的一站式三维GIS数据编辑、转换、发布平台&#xff0c;凭借其独特的“RVT切片器”功能&#xff0c;在RVT图元处理方面也有着不俗的表现…...

Appium+python自动化(十二)- Android UIAutomator

Android团队在4.1版本&#xff08;API 16&#xff09;中推出了一款全新的UI自动化测试工具UiAutomator&#xff0c;用来帮助开发人员更有效率的完成App的Debug工作&#xff0c;同时对于测试人员也是一大福音&#xff0c;为什么这么说呢&#xff1f; UiAutomator提供了以下两种…...

在C语言中使用UUID作为AES加密密钥

在C语言中使用UUID作为AES加密密钥 编译依赖安装示例代码编译和运行关键点说明![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0df1f1d803cd40688f6d58a9d0e1f1d9.png)注意事项编译依赖安装 运行环境位centos8 Linux 4.18.0-348.7.1.el8_5.x86_64 #1 SMP Wed Dec …...

Nginx+Tomcat负载均衡集群

目录 一、Tomcat 基础与单节点部署 &#xff08;一&#xff09;Tomcat 概述 &#xff08;二&#xff09;单节点部署案例 1. 案例环境 2. 实施准备 3. 安装 JDK 4. 查看 JDK 安装情况 5. 安装配置 Tomcat 6. 启动 Tomcat 7. 访问测试 8. 关闭 Tomcat &#xff08;三…...

QQ邮箱发送验证码(Springboot)

一、邮箱发送服务准备 在qq邮箱的设置中选择账号下开启服务。 开启时可能会有短信验证&#xff0c;开启后显示验证码之类的一串英文&#xff0c;复制保存起来&#xff0c;在配置文件中会使用到。 二、后端依赖及配置 依赖 在pom.yml文件中添加相关依赖&#xff0c;redis的…...

Python Copilot【代码辅助工具】 简介

粉丝爱买鳕鱼肠深海鳕鱼肉鱼肉香肠盼盼麦香鸡味块卡乐比&#xff08;Calbee&#xff09;薯条三兄弟 独立小包美丽雅 奶茶杯一次性饮料杯好时kisses多口味巧克力糖老金磨方【黑金系列】黑芝麻丸郑新初网红郑新初烤鲜牛肉干超人毛球修剪器去球器剃毛器衣服去毛器优惠券宁之春 红黑…...

如何写高效的Prompt?

概述 提示词(Prompt)的质量将直接影响模型生成结果的质量&#xff0c;所以精心设计一个让大模型能够理解并有效回复的提示词是至关重要的。本文内容自论文中获取&#xff1a;https://arxiv.org/pdf/2312.16171 介绍了5类共计26条提示词书写原则。 书写原则 类别原则备注快速…...

【EF Core】 EF Core并发控制:乐观锁与悲观锁的应用

文章目录 前言一、并发的风险二、EF Core中的并发控制方式2.1 开放式并发&#xff08;乐观锁&#xff09;2.1.1 应用程序管理的属性并发令牌2.1.2 数据库生成的并发令牌 2.2 悲观锁 总结 前言 实际的生产环境中&#xff0c;我们经常能遇到数据库由多个应用程序同时使用。每个程…...

WaytoAGI东京大会开启AI全球化新对话:技术无国界,合作促创新

全球AI专家齐聚东京&#xff0c;一场关于技术无国界的对话正在进行。 2025年6月7日&#xff0c;一场备受瞩目的AI盛会——“WaytoAGI全球AI大会东京站”在日本东京樱美林大学新宿校区正式拉开帷幕。这场为期两天的会议&#xff08;6月7日至8日&#xff09;由国内最大的AI开源知…...

Harmony核心:动态方法修补与.NET游戏Mod开发

一、Harmony的核心定位与设计哲学 Harmony是一个运行时动态方法修补库&#xff0c;专为修改已编译的.NET/Mono应用程序而设计&#xff0c;尤其适用于游戏Mod开发。其核心创新在于&#xff1a; 非破坏性修改&#xff1a;保留原始方法完整性&#xff0c;避免直接替换或覆盖。多…...

AI系统应用开发工程师

以下是对AI系统应用开发与运维岗位的梳理整合&#xff0c;从企业、岗位、任务、能力等维度进行分类呈现&#xff0c;便于清晰对比两者的工作侧重&#xff1a; 一、代表性企业对比 分类企业名称应用开发方向中移系统集成有限公司、科大讯飞河北科技有限公司、华为技术服务有限…...

Qt Test功能及架构

Qt Test 是 Qt 框架中的单元测试模块&#xff0c;在 Qt 6.0 中提供了全面的测试功能。 一、主要功能 核心功能 1. 单元测试框架 提供完整的单元测试基础设施 支持测试用例、测试套件的组织和执行 包含断言宏和测试结果收集 2. 测试类型支持 单元测试&#xff1a;对单个函…...

图像处理、图像分析和图像理解的定义、联系与区别

1. 定义 图像处理&#xff08;Image Processing&#xff09; 图像处理是低层操作&#xff0c;主要针对像素级的图像数据进行加工&#xff0c;目的是改善图像质量或为后续分析做准备。 典型任务&#xff1a;去噪、增强&#xff08;如对比度调整&#xff09;、锐化、边缘检测、图…...

【Java开发日记】说一说 SpringBoot 中 CommandLineRunner

目录 1、CommandLineRunner SpringBoot中CommandLineRunner的作用 简单例子 多个类实现CommandLineRunner接口执行顺序的保证 通过实现Ordered接口实现控制执行顺序 通过Order注解实现控制执行顺序 Order 作用 2、ApplicationRunner 3、传递参数 4、源码跟踪 run()方…...

全面理解 Linux 内核性能问题:分类、实战与调优策略

在 Linux 系统&#xff08;特别是嵌入式或服务器环境&#xff09;中&#xff0c;性能问题往往错综复杂、表象多变。只有对常见性能问题进行系统归类、理解其症状与根源&#xff0c;才能有效定位和解决。本文将围绕八大类核心性能问题&#xff0c;结合实战示例&#xff0c;逐类分…...

算法-多条件排序

1、数对排序的使用 pair<ll,ll> a[31];//cmp为比较规则 ll cmp(pair<ll,ll>a,pair<ll,ll>b){if(a.first!b.first)return a.first>b.first;else return a.second<b.second; }//按照比较规则进行排序 sort(a1,a31,cmp); 2、具体例题 输入样例&#xff1…...

DelayQueue、ScheduledThreadPoolExecutor 和 PriorityBlockingQueue :怎么利用堆实现定时任务

DelayQueue DelayQueue 的最大亮点&#xff1a; 并不是简单全局锁的“单调队列”实现&#xff0c;而是用Leader-Follower 模式极大减少了线程唤醒的开销。插入与唤醒、等待与 leader 变更&#xff0c;都通过巧妙的锁和条件变量组合完成。 如果只关注“线程安全的优先队列全局…...

Kafka 消息模式实战:从简单队列到流处理(二)

四、Kafka 流处理实战 4.1 Kafka Streams 简介 Kafka Streams 是 Kafka 提供的流处理库&#xff0c;它为开发者提供了一套简洁而强大的 API&#xff0c;用于构建实时流处理应用程序。Kafka Streams 基于 Kafka 的高吞吐量、分布式和容错特性&#xff0c;能够处理大规模的实时…...

大数据(2) 大数据处理架构Hadoop

一、Hadoop简介 1.定义 Hadoop 是一个开源的分布式计算框架&#xff0c;由 Apache 基金会开发&#xff0c;用于处理海量数据&#xff0c;具备高可靠性、高扩展性和高容错性。它主要由两个核心模块组成&#xff1a; HDFS&#xff08;Hadoop Distributed File System&#xff09…...

【Kotlin】注解反射扩展

文章目录 注解用法反射类引用 扩展扩展函数的作用域成员方法优先级总高于扩展函数 被滥用的扩展函数扩展属性静态扩展 标准库中的扩展函数 使用 T.also 函数交换两个变量sNullOrEmpty | isNullOrBlankwith函数repeat函数 调度方式对扩展函数的影响静态与动态调度扩展函数始终静…...

固定ip和非固定ip的区别是什么?如何固定ip地址

在互联网中&#xff0c;我们常会接触到固定IP和非固定IP的概念。它们究竟有何不同&#xff1f;如何固定IP地址&#xff1f;让我们一起来探究这个问题。 一、固定IP和非固定IP的区别是什么 固定IP&#xff08;静态IP&#xff09;和非固定IP&#xff08;动态IP&#xff09;是两种…...

升级centos 7.9内核到 5.4.x

前面是指南&#xff0c;后面是工作日志。 wget http://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/kernel-lt-devel-5.4.225-1.el7.elrepo.x86_64.rpm wget http://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/kernel-lt-5.4.2…...

Nginx 安全设置配置

1、增加header公共文件 文件地址&#xff1a;/etc/nginx/conf.d/security_headers.conf # XSS防护配置add_header X-XSS-Protection "1; modeblock" always; # 其他安全配置add_header X-Content-Type-Options "nosniff";add_header X-Frame-Options &qu…...

协程的常用阻塞函数

以下是一些常见的阻塞函数示例&#xff1a; 1. **Thread.sleep()** 阻塞当前线程一段时间。 kotlin Thread.sleep(1000) // 阻塞线程 1 秒 2. **InputStream.read()** 从输入流中读取数据时会阻塞&#xff0c;直到有数据可用或流结束。 kotlin val inputStream FileInputStre…...

探索NoSQL注入的奥秘:如何消除MongoDB查询中的前置与后置条件

随着互联网技术的飞速发展&#xff0c;数据库作为信息存储与管理的核心&#xff0c;其安全性问题日益凸显。近年来&#xff0c;NoSQL数据库因其灵活性和高性能逐渐成为许多企业的首选&#xff0c;其中MongoDB以其文档存储和JSON-like查询语言在开发社区中广受欢迎。然而&#x…...

使用矩阵乘法+线段树解决区间历史和问题的一种通用解法

文章目录 前言P8868 [NOIP2022] 比赛CF1824DP9990/2020 ICPC EcFinal G 前言 一般解决普通的区间历史和&#xff0c;只需要定义辅助 c h s − t ⋅ a chs-t\cdot a chs−t⋅a&#xff0c; h s hs hs是历史和&#xff0c; a a a是区间和&#xff0c; t t t是时间戳&#xff0c…...