Java 编码系列:线程基础与最佳实践
引言
在多任务处理和并发编程中,线程是不可或缺的一部分。Java 提供了丰富的线程管理和并发控制机制,使得开发者可以轻松地实现多线程应用。本文将深入探讨 Java 线程的基础知识,包括 Thread 类、Runnable 接口、Callable 接口以及线程的生命周期,并结合大厂的最佳实践和底层核心原理,帮助读者全面掌握这些关键技术。
1. 线程基础
1.1 什么是线程
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含多个线程,这些线程共享进程的资源,如内存和文件句柄。
1.2 线程的优势
- 提高响应速度:通过多线程,可以同时执行多个任务,提高应用程序的响应速度。
- 资源共享:线程共享进程的资源,减少了资源开销。
- 简化编程模型:多线程编程模型使得复杂的任务可以分解为多个简单的任务并行执行。
2. 创建线程的方式
2.1 继承 Thread 类
通过继承 Thread 类并重写 run 方法,可以创建一个新的线程。
class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程 " + Thread.currentThread().getName() + " 运行中...");}
}public class ThreadExample {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start(); // 启动线程}
}
2.2 实现 Runnable 接口
通过实现 Runnable 接口并实现 run 方法,可以创建一个新的线程。这种方式更加灵活,因为一个 Runnable 对象可以被多个线程共享。
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程 " + Thread.currentThread().getName() + " 运行中...");}
}public class RunnableExample {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable, "MyThread");thread.start(); // 启动线程}
}
2.3 实现 Callable 接口
Callable 接口类似于 Runnable,但它可以返回一个结果,并且可以抛出异常。Callable 接口通常与 Future 和 ExecutorService 一起使用。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i < 100; i++) {sum += i;}return sum;}
}public class CallableExample {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);Future<Integer> future = executorService.submit(new MyCallable());try {int result = future.get(); // 获取结果System.out.println("计算结果: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();} finally {executorService.shutdown(); // 关闭线程池}}
}
3. 线程的生命周期
3.1 线程状态
Java 线程有以下几种状态:
- New:线程被创建但尚未启动。
- Runnable:线程正在 JVM 中运行,但可能在等待操作系统资源。
- Blocked:线程被阻塞,等待监视器锁。
- Waiting:线程在等待另一个线程执行特定操作。
- Timed Waiting:线程在等待指定的时间。
- Terminated:线程已退出。
3.2 线程状态转换
- New -> Runnable:调用
start方法。 - Runnable -> Blocked:尝试获取已被其他线程持有的锁。
- Runnable -> Waiting:调用
wait、join或LockSupport.park方法。 - Runnable -> Timed Waiting:调用
sleep、wait(long)、join(long)或LockSupport.parkNanos方法。 - Blocked -> Runnable:获取到所需的锁。
- Waiting -> Runnable:等待的条件满足。
- Timed Waiting -> Runnable:等待时间到期。
- Runnable -> Terminated:线程的
run方法执行完毕或因未捕获的异常而终止。
4. 线程同步
4.1 同步方法
通过在方法上使用 synchronized 关键字,可以确保同一时间只有一个线程可以访问该方法。
public class SynchronizedMethodExample {private int count = 0;public synchronized void increment() {count++;}public static void main(String[] args) {SynchronizedMethodExample example = new SynchronizedMethodExample();Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("最终计数: " + example.count);}
}
4.2 同步代码块
通过在代码块上使用 synchronized 关键字,可以确保同一时间只有一个线程可以访问该代码块。
public class SynchronizedBlockExample {private int count = 0;private final Object lock = new Object();public void increment() {synchronized (lock) {count++;}}public static void main(String[] args) {SynchronizedBlockExample example = new SynchronizedBlockExample();Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("最终计数: " + example.count);}
}
5. 线程间通信
5.1 wait 和 notify 方法
wait 和 notify 方法用于线程间的通信。wait 方法使当前线程进入等待状态,notify 方法唤醒一个等待的线程。
public class WaitNotifyExample {private final Object lock = new Object();private boolean flag = false;public void producer() {synchronized (lock) {while (flag) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 生产数据System.out.println("生产数据");flag = true;lock.notify();}}public void consumer() {synchronized (lock) {while (!flag) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 消费数据System.out.println("消费数据");flag = false;lock.notify();}}public static void main(String[] args) {WaitNotifyExample example = new WaitNotifyExample();Thread producerThread = new Thread(() -> {for (int i = 0; i < 5; i++) {example.producer();}});Thread consumerThread = new Thread(() -> {for (int i = 0; i < 5; i++) {example.consumer();}});producerThread.start();consumerThread.start();}
}
6. 线程池
6.1 什么是线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池可以有效控制运行的线程数量,减少创建和销毁线程的开销。
6.2 创建线程池
Java 提供了 ExecutorService 接口和 Executors 工具类来创建和管理线程池。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);for (int i = 0; i < 5; i++) {int taskId = i;executorService.execute(() -> {System.out.println("任务 " + taskId + " 在线程 " + Thread.currentThread().getName() + " 上运行");});}executorService.shutdown(); // 关闭线程池}
}
7. 大厂最佳实践
7.1 阿里巴巴《Java开发手册》
- 避免滥用线程:合理使用线程池,避免频繁创建和销毁线程。
- 同步方法优先:在多线程环境中,优先使用同步方法或同步代码块。
- 避免死锁:设计线程同步时,避免出现死锁的情况。
7.2 Google Java Style Guide
- 线程安全:确保多线程环境下的代码是线程安全的。
- 资源管理:使用
try-with-resources语句管理资源,确保资源在使用后正确释放。 - 异常处理:合理处理线程中的异常,避免未捕获的异常导致线程终止。
7.3 Oracle 官方文档
- 线程池:推荐使用
ExecutorService来管理线程池,提高线程的复用率。 - 线程同步:使用
synchronized关键字或ReentrantLock来实现线程同步。 - 线程间通信:使用
wait和notify方法实现线程间的通信。
8. 底层核心原理
8.1 线程调度
- 时间片轮转:操作系统通过时间片轮转的方式调度线程,每个线程在分配的时间片内运行。
- 优先级:线程的优先级决定了线程被调度的频率,优先级高的线程更有可能被调度。
8.2 线程同步
- 锁机制:
synchronized关键字和ReentrantLock都是基于锁机制实现的线程同步。 - 监视器锁:
synchronized关键字使用的是监视器锁(Monitor),每个对象都有一个监视器锁。
8.3 线程间通信
- 等待/通知机制:
wait和notify方法通过等待/通知机制实现线程间的通信。 - 条件变量:
Condition接口提供了更灵活的等待/通知机制,可以替代wait和notify。
9. 示例代码
9.1 继承 Thread 类
class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程 " + Thread.currentThread().getName() + " 运行中...");}
}public class ThreadExample {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start(); // 启动线程}
}
9.2 实现 Runnable 接口
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程 " + Thread.currentThread().getName() + " 运行中...");}
}public class RunnableExample {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable, "MyThread");thread.start(); // 启动线程}
}
9.3 实现 Callable 接口
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i < 100; i++) {sum += i;}return sum;}
}public class CallableExample {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(2);Future<Integer> future = executorService.submit(new MyCallable());try {int result = future.get(); // 获取结果System.out.println("计算结果: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();} finally {executorService.shutdown(); // 关闭线程池}}
}
9.4 线程同步
public class SynchronizedMethodExample {private int count = 0;public synchronized void increment() {count++;}public static void main(String[] args) {SynchronizedMethodExample example = new SynchronizedMethodExample();Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("最终计数: " + example.count);}
}
9.5 线程间通信
public class WaitNotifyExample {private final Object lock = new Object();private boolean flag = false;public void producer() {synchronized (lock) {while (flag) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 生产数据System.out.println("生产数据");flag = true;lock.notify();}}public void consumer() {synchronized (lock) {while (!flag) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 消费数据System.out.println("消费数据");flag = false;lock.notify();}}public static void main(String[] args) {WaitNotifyExample example = new WaitNotifyExample();Thread producerThread = new Thread(() -> {for (int i = 0; i < 5; i++) {example.producer();}});Thread consumerThread = new Thread(() -> {for (int i = 0; i < 5; i++) {example.consumer();}});producerThread.start();consumerThread.start();}
}
10. 总结
本文深入探讨了 Java 线程的基础知识,包括 Thread 类、Runnable 接口、Callable 接口以及线程的生命周期,并结合大厂的最佳实践和底层核心原理,帮助读者全面掌握这些关键技术。合理地使用线程管理机制可以提高程序的性能和响应速度,避免线程安全问题。希望本文对你有所帮助,如果你有任何问题或建议,欢迎留言交流。
希望这篇文章能够满足你的需求,如果有任何进一步的问题或需要更多内容,请随时告诉我!
相关文章:
Java 编码系列:线程基础与最佳实践
引言 在多任务处理和并发编程中,线程是不可或缺的一部分。Java 提供了丰富的线程管理和并发控制机制,使得开发者可以轻松地实现多线程应用。本文将深入探讨 Java 线程的基础知识,包括 Thread 类、Runnable 接口、Callable 接口以及线程的生命…...
《深度学习》—— ResNet 残差神经网络
文章目录 一、什么是ResNet?二、残差结构(Residual Structure)三、Batch Normalization(BN----批归一化) 一、什么是ResNet? ResNet 网络是在 2015年 由微软实验室中的何凯明等几位大神提出,斩获…...
针对考研的C语言学习(定制化快速掌握重点3)
1.数组常见错误 数组传参实际传递的是数组的起始地址,若在函数中改变数组内容,数组本身也会发生变化 #include<stdio.h> void change_ch(char* str) {str[0] H; } int main() {char ch[] "hello";change_ch(ch);printf("%s\n&q…...
pikachu XXE(XML外部实体注入)通关
靶场:pikachu 环境: 系统:Windows10 服务器:PHPstudy2018 靶场:pikachu 关卡提示说:这是一个接收xml数据的api 常用的Payload 回显 <?xml version"1.0"?> <!DOCTYPE foo [ <!ENTITY …...
shell脚本定时任务通知到钉钉
shell脚本定时任务通知到钉钉 1、背景 前两天看了一下定时任务,垃圾清理、日志相关、系统巡检这些,有的服务器运行就有问题,或者不运行,正好最近在做运维标准重制运维手册,顺便把自动化这块优化一下,所…...
2.4K star的GOT-OCR2.0:端到端OCR 模型
GOT-OCR2.0是一款新一代的光学字符识别(OCR)技术,标志着人工智能在文本识别领域的重大进步。作为一款开源模型,GOT-OCR2.0不仅支持传统的文本和文档识别,还能够处理乐谱、图表以及复杂的数学公式,为用户提供…...
【JavaEE】——线程的安全问题和解决方式
阿华代码,不是逆风,就是我疯,你们的点赞收藏是我前进最大的动力!!希望本文内容能够帮助到你! 目录 一:问题引入 二:问题深入 1:举例说明 2:图解双线程计算…...
初步认识了解分布式系统
背景认识:我们要学习redis,还是得了解一下什么是分布式。为什么呢?因为redis只有在分布式系统中才能发挥它最大的作用,也就是领域展开,所以接下来我们就简单过一下什么是分布式系统 一些术语认识: &#x…...
react 为什么不能学习 vue3 进行静态节点标记优化性能?
因为 React 使用的是 JSX,而 JSX 本质上就是 JS 语言,是具有非常高的动态的,而 Vue 使用的 template 则是给了足够的约束,比如说 Vue 的 template 里面使用了很多特定的标记来做不同的事情,比如说 v-if 就是进行变量判…...
Elasticsearch黑窗口启动乱码问题解决方案
问题描述 elasticsearch启动后有乱码现象 解决方案: 提示:这里填写该问题的具体解决方案: 到 \config 文件下找到 jvm.options 文件 打开后 在文件末尾空白处 添加 -Dfile.encodingGBK 保存后重启即可。...
Logtus IT员工参加国际技术大会
Logtus IT的员工参加了国际技术大会,该大会致力于在金砖国家框架内开发俄罗斯的技术。该活动包括一个展览,俄罗斯开发商展示了他们的信息技术、电子和电信成就。展示了面向国内和国际市场(包括政府机构)的解决方案、产品和平台。 …...
ant design vue组件中table组件设置分组头部和固定总结栏
问题:遇到了个需求,不仅要设置分组的头部,还要在顶部有个统计总和的栏。 分组表头的配置主要是这个,就是套娃原理,不需要展示数据的直接写个title就行,需要展示数据的字段才需要详细的配置属性。 const co…...
2024年信息安全企业CRM选型与应用研究报告
数字化的生活给人们带来便利的同时也带来一定的信息安全隐患,如网络侵权、泄露用户隐私、黑客攻击等。在互联网高度发展的今天,信息安全与我们每个人、每个组织甚至每个国家都息息相关。 信息安全行业蓬勃发展。根据智研咨询数据,2021年&…...
【后端开发】JavaEE初阶——计算机是如何工作的???
前言: 🌟🌟本期讲解计算机工作原理,希望能帮到屏幕前的你。 🌈上期博客在这里:【MySQL】MySQL中JDBC编程——MySQL驱动包安装——(超详解) 🌈感兴趣的小伙伴看一看小编主…...
Linux(Ubuntu)源码安装postgresql16.3
文章目录 Linux(Ubuntu)源码安装postgresql016.3下载程序包编译安装软件初次执行configure错误调试1:configure: error: ICU library not found再次执行configureBuild 设置环境初始化数据库启动数据库参考 Linux(Ubuntu)源码安装…...
Python 入门教程(7)面向对象 | 7.6、多态
文章目录 一、多态1、鸭子类型2、实现多态的机制2.1、鸭子类型2.2、继承与重写 3、Python多态的优势4、总结 前言: 在面向对象编程(OOP)中,多态(Polymorphism)是一种非常重要的概念,多态就是同一…...
Cilium + ebpf 系列文章-什么是ebpf?(一)
前言: 这篇非常非常干,很有可能读不懂。 这里非常非常推荐,建议使用Cilium官网的lab来辅助学习!!!Resources Library - IsovalentExplore Isovalents Resource Library, your one-stop destination for ins…...
RabbitMQ08_保证消息可靠性
保证消息可靠性 一、生产者可靠性1、生产者重连机制(防止网络波动)2、生产者确认机制Publisher Return 确认机制Publisher Confirm 确认机制 二、MQ 可靠性1、数据持久化交换机、队列持久化消息持久化 2、Lazy Queue 惰性队列 三、消费者可靠性1、消费者…...
恶意Bot流量识别分析实践
1、摘要 随着互联网的发展,自动化工具和脚本(Bots)的使用越来越普遍。虽然一些善意 Bots 对于网站的正常运行和数据采集至关重要,但恶意 Bots 可能会对网站带来负面影响,如爬取敏感信息、恶意注册、刷流量等。因此&am…...
Java2 实用教程(第6版)习题2 第四题
【源文件的命名与书中的不同】 四、阅读程序题 1、上机运行下列程序,注意观察输出的结果。 public class E2_1 {public static void main(String args[]){for(int i20302;i<20322;i){System.out.println((char) i);}} } 运行结果: 低 住 佐 佑 佒…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门  > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
