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

Java 之多线程高级

本文将深入探讨Java线程池的方方面面,从线程状态介绍开始,逐步深入线程池的原理、Executors默认线程池的使用,自定义线程池的创建,ThreadPoolExecutor的参数详解,以及非默认任务拒绝策略的应用。最后,我们将通过一个小案例来展示如何使用线程池来提高程序效率。

1. 线程状态介绍

Java线程的生命周期可以用以下状态来描述:

  • 新建 (New): 线程对象被创建但还未启动。

  • 可运行 (Runnable): 线程已经启动,正在等待获取 CPU 时间片执行。

  • 运行 (Running): 线程获得了 CPU 时间片,正在执行任务。

  • 阻塞 (Blocked): 线程正在等待某些事件发生,例如 I/O 操作完成、获取锁等。

  • 等待 (Waiting): 线程正在等待其他线程通知它才能继续执行。

  • 超时等待 (Timed Waiting): 线程正在等待其他线程通知它,但有一个超时时间限制。

  • 终止 (Terminated): 线程已经执行完毕,无法再次启动。

代码示例:

public class ThreadStateDemo {public static void main(String[] args) {// 创建一个新的线程Thread thread = new Thread(() -> {// 模拟线程运行逻辑System.out.println("线程正在运行...");try {// 模拟阻塞操作Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程运行结束...");});// 启动线程thread.start();// 获取线程状态并打印System.out.println("线程状态:" + thread.getState()); }
}

2. 线程池---基本原理

线程池是一种管理和复用线程的技术,它通过维护一组可重用线程来处理任务,避免频繁创建和销毁线程带来的性能开销。

基本原理:

  • 线程池维护一个工作线程集合: 用于执行提交的任务。

  • 任务队列: 用于存储等待执行的任务。

  • 任务提交: 当有新的任务提交时,线程池会判断是否有空闲线程,如果有则直接分配任务给该线程执行,否则将任务加入任务队列等待。

  • 线程回收: 当线程执行完任务后,不会立即销毁,而是进入等待状态,等待新的任务分配。

优势:

  • 减少创建和销毁线程的开销: 重用线程可以避免频繁创建和销毁线程带来的性能损耗。

  • 控制并发线程数量: 可以有效地控制并发线程数,避免资源耗尽。

  • 提高响应速度: 当任务提交时,如果线程池中有空闲线程,可以立即执行任务,提高响应速度。

  • 简化线程管理: 通过线程池可以方便地管理线程,无需手动创建和销毁线程。

3. 线程池---Executors默认线程池

java.util.concurrent.Executors 类提供了一些常用的线程池创建方法,包括:

  • newCachedThreadPool(): 创建一个可缓存的线程池,如果线程池长度超过处理需要,可回收空闲线程,如果没有空闲线程则创建新的线程。

  • newFixedThreadPool(int nThreads): 创建一个固定线程数的线程池,如果提交的任务数超过线程数,则会将任务放入队列等待。

  • newSingleThreadExecutor(): 创建一个单线程化的线程池,保证任务按照顺序执行。

  • newScheduledThreadPool(int corePoolSize): 创建一个可以执行延迟任务或周期性任务的线程池。

代码示例:

public class ExecutorsDemo {public static void main(String[] args) {// 创建一个缓存线程池ExecutorService cachedThreadPool = Executors.newCachedThreadPool();// 创建一个固定线程数的线程池ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);// 创建一个单线程化的线程池ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();// 创建一个可以执行延迟任务或周期性任务的线程池ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);}
}

4. 线程池---Executors创建指定上限的线程池

可以使用 Executors 类中的 newFixedThreadPool(int nThreads) 方法来创建指定上限的线程池。

代码示例:

public class FixedThreadPoolDemo {public static void main(String[] args) {// 创建一个固定线程数为 5 的线程池ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);// 提交任务到线程池for (int i = 0; i < 10; i++) {fixedThreadPool.execute(() -> {// 模拟任务执行逻辑System.out.println("线程池中的线程正在执行任务...");});}// 关闭线程池fixedThreadPool.shutdown();}
}

5. 线程池---ThreadPoolExecutor

java.util.concurrent.ThreadPoolExecutor 类是创建线程池的核心类,它提供了更加灵活的线程池配置方式。

代码示例:

public class ThreadPoolExecutorDemo {public static void main(String[] args) {// 创建一个线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(5, // corePoolSize:核心线程数10, // maximumPoolSize:最大线程数60, // keepAliveTime:空闲线程存活时间TimeUnit.SECONDS, // unit:空闲线程存活时间单位new LinkedBlockingQueue<>(100), // workQueue:任务队列new ThreadPoolExecutor.AbortPolicy() // handler:任务拒绝策略);// 提交任务到线程池for (int i = 0; i < 10; i++) {executor.execute(() -> {// 模拟任务执行逻辑System.out.println("线程池中的线程正在执行任务...");});}// 关闭线程池executor.shutdown();}
}

6. 线程池---参数详解(创建线程池对象的参数)

  • corePoolSize: 核心线程数,即使线程池处于空闲状态,也始终保持核心线程数数量的线程存活。

  • maximumPoolSize: 最大线程数,当任务队列已满且线程池中线程数量小于最大线程数时,会创建新的线程来处理任务,直到线程数量达到最大线程数。

  • keepAliveTime: 空闲线程存活时间,当线程池中线程数量超过核心线程数时,如果空闲线程在 keepAliveTime 时间内没有新的任务提交,则会回收该线程。

  • unit: 空闲线程存活时间单位。

  • workQueue: 任务队列,用于存放等待执行的任务。

  • threadFactory:  创建线程工厂,不能为null

  • handler: 任务拒绝策略,当任务队列已满且线程池中线程数量达到最大线程数时,会触发任务拒绝策略。

详解如下:

                1.corePoolSize:核心线程的最大值,不能小于0
                2.maximumPoolSize:最大线程数,不能小于等于0,maximumPoolSize >= corePoolSize
                3.keepAliveTime:  空闲线程最大存活时间,不能小于0
                4.unit:时间单位
                5.workQueue:任务队列,不能为null
                6.threadFactory:创建线程工厂,不能为null      
                7.handler:任务的拒绝策略,不能为null 

代码示例:

public class ThreadPoolExecutorDemo {public static void main(String[] args) {// 创建一个线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(5, // corePoolSize:核心线程数10, // maximumPoolSize:最大线程数60, // keepAliveTime:空闲线程存活时间TimeUnit.SECONDS, // unit:空闲线程存活时间单位new LinkedBlockingQueue<>(100), // workQueue:任务队列new ThreadPoolExecutor.AbortPolicy() // handler:任务拒绝策略);// 提交任务到线程池for (int i = 0; i < 10; i++) {executor.execute(() -> {// 模拟任务执行逻辑System.out.println("线程池中的线程正在执行任务...");});}// 关闭线程池executor.shutdown();}
}

7. 线程池---非默认任务拒绝策略

当任务队列已满且线程池中线程数量达到最大线程数时,会触发任务拒绝策略。ThreadPoolExecutor 类提供了一些默认的任务拒绝策略,也可以自定义任务拒绝策略。

  • AbortPolicy: 抛出 RejectedExecutionException 异常,这是默认的拒绝策略。

  • CallerRunsPolicy: 由提交任务的线程执行该任务,可以防止线程池被阻塞。

  • DiscardPolicy: 直接丢弃任务,不做任何处理。

  • DiscardOldestPolicy: 丢弃队列中最老的任务,然后尝试重新提交当前任务。

代码示例:

// 使用 CallerRunsPolicy 作为拒绝策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,10,60,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),new ThreadPoolExecutor.CallerRunsPolicy()
);// 使用自定义拒绝策略
class MyRejectionHandler implements RejectedExecutionHandler {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {System.out.println("任务被拒绝,执行自定义处理逻辑...");}
}ThreadPoolExecutor executor = new ThreadPoolExecutor(5,10,60,TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),new MyRejectionHandler()
);

小案例: 使用线程池下载多个文件

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolDownload {public static void main(String[] args) {// 创建一个固定线程数为 5 的线程池ExecutorService executor = Executors.newFixedThreadPool(5);// 要下载的文件 URLString[] fileUrls = {"https://www.example.com/file1.zip","https://www.example.com/file2.txt","https://www.example.com/file3.jpg","https://www.example.com/file4.pdf","https://www.example.com/file5.mp4"};// 提交下载任务到线程池for (String fileUrl : fileUrls) {executor.execute(() -> downloadFile(fileUrl));}// 关闭线程池executor.shutdown();}// 下载文件private static void downloadFile(String fileUrl) {try {URL url = new URL(fileUrl);ReadableByteChannel rbc = Channels.newChannel(url.openStream());FileOutputStream fos = new FileOutputStream(fileUrl.substring(fileUrl.lastIndexOf('/') + 1));fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);fos.close();rbc.close();System.out.println("下载成功:" + fileUrl);} catch (IOException e) {System.err.println("下载失败:" + fileUrl + " - " + e.getMessage());}}
}

总结:

本文详细介绍了 Java 线程池的基础知识,从线程状态、线程池的基本原理、Executors默认线程池、自定义线程池的创建、ThreadPoolExecutor的参数详解,以及非默认任务拒绝策略等方面进行了深入讲解。最后,通过一个小案例展示了如何使用线程池来提高程序效率。希望本文能够帮助各位看官更好地理解和运用 Java 线程池,从而提升代码效率和性能。感谢各位看官的观看,下期见,谢谢~

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 安卓13系统导航方式分析以及安卓13修改默认方式为手势导航 android13修改导航方式
  • 828华为云征文|华为Flexus云服务器搭建Cloudreve私人网盘
  • Java中的红黑树(如果想知道Java中有关红黑树的知识点,那么只看这一篇就足够了!)
  • 【渗透测试】-vulnhub源码框架漏洞-Os-hackNos-1
  • 运维工程师面试整理-数据库
  • el-input设置type=‘number‘和v-model.number的区别
  • Longman Dictionary of Contemporary English (朗文当代高级英语辞典)
  • 【ARM】Trustzone和安全架构
  • golang学习笔记18——golang 访问 mysql 数据库全解析
  • Amoco:一款针对二进制源码的安全分析工具
  • HC-SR04超声波传感器详解(STM32)
  • scantf
  • k8s介绍及部署
  • 【Kubernetes】常见面试题汇总(二十四)
  • PWN二进制安全修仙秘籍【第一章#工具篇01】WLS配置tmux分屏、oh-my-zsh命令补全
  • 【comparator, comparable】小总结
  • 【剑指offer】让抽象问题具体化
  • CentOS从零开始部署Nodejs项目
  • chrome扩展demo1-小时钟
  • docker-consul
  • in typeof instanceof ===这些运算符有什么作用
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • MySQL数据库运维之数据恢复
  • Python十分钟制作属于你自己的个性logo
  • Spring-boot 启动时碰到的错误
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 关于for循环的简单归纳
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 面试总结JavaScript篇
  • 模型微调
  • 前端存储 - localStorage
  • 什么软件可以剪辑音乐?
  • 微信小程序设置上一页数据
  • 智能网联汽车信息安全
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • const的用法,特别是用在函数前面与后面的区别
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​secrets --- 生成管理密码的安全随机数​
  • ‌前端列表展示1000条大量数据时,后端通常需要进行一定的处理。‌
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • #laravel部署安装报错loadFactoriesFrom是undefined method #
  • #NOIP 2014#Day.2 T3 解方程
  • (12)Hive调优——count distinct去重优化
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (超详细)语音信号处理之特征提取
  • (第30天)二叉树阶段总结
  • (分布式缓存)Redis持久化
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (附源码)springboot教学评价 毕业设计 641310
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (数据大屏)(Hadoop)基于SSM框架的学院校友管理系统的设计与实现+文档
  • (四)React组件、useState、组件样式