Java多线程(四)、线程池

Java多线程并发编程系列-00 线程池原理与自定义实现线程池 本文探讨了Java多线程并发编程中的线程池原理与实现。多线程的核心目的是充分利用CPU资源并发执行任务,但线程并非越多越好,需权衡创建/销毁开销、内存消耗及上下文切换成本。线程池通过固定数量的工作线程和任务队列(BlockingQueue)实现高效任务调度:任务提交到队列,空闲线程获取任务执行。针对计算型与IO型任务,线程数需动态调整(如CPU核数的1-2倍或更高)。文中还实现了一个简易线程池(FixedSizeThreadPool),包含任务队列、工作线程集合及关闭逻辑,并对比了阻塞(put/ta 阅读详情
Java多线程(四)、线程池

系统启动一个新线程的成本是比较高的,因为它涉及到与操作系统的交互。在这种情况下,使用线程池可以很好的提供性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池。

与数据库连接池类似的是,线程池在系统启动时即创建大量空闲的线程,程序将一个Runnable对象传给线程池,线程池就会启动一条线程来执行该对象的run方法,当run方法执行结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个Runnable对象的run方法。

除此之外,使用线程池可以有效地控制系统中并发线程的数量,但系统中包含大量并发线程时,会导致系统性能剧烈下降,甚至导致JVM崩溃。而线程池的最大线程数参数可以控制系统中并发的线程不超过此数目。

在JDK1.5之前,开发者必须手动的实现自己的线程池,从JDK1.5之后,Java内建支持线程池。

与多线程并发的所有支持的类都在java.lang.concurrent包中。我们可以使用里面的类更加的控制多线程的执行。


一、Executors类

JDK1.5中提供Executors工厂类来产生连接池,该工厂类中包含如下的几个静态工程方法来创建连接池:

1、public static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用的、具有固定线程数的线程池。

2、public static ExecutorService newSingleThreadExecutor():创建一个只有单线程的线程池,它相当于newFixedThreadPool方法是传入的参数为1

3、public static ExecutorService newCachedThreadPool():创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将会被缓存在线程池中。

4、public static ScheduledExecutorService newSingleThreadScheduledExecutor:创建只有一条线程的线程池,他可以在指定延迟后执行线程任务

5、public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize):创建具有指定线程数的线程池,它可以再指定延迟后执行线程任务,corePoolSize指池中所保存的线程数,即使线程是空闲的也被保存在线程池内。

上面的几个方法都有一个重载的方法,多传入一个ThreadFactory参数的重载方法,使用的比较少。


二、ExecutorService类

可以看到上面的5个方法中,前面3个方法的返回值都是一个ExecutorService对象。该ExecutorService对象就代表着一个尽快执行线程的线程池(只要线程池中有空闲线程立即执行线程任务),程序只要将一个Runnable对象或Callable对象提交给该线程池即可,该线程就会尽快的执行该任务。

ExecutorService有几个重要的方法:

方法摘要
 booleanisShutdown()
          如果此执行程序已关闭,则返回 true。
 booleanisTerminated()
          如果关闭后所有任务都已完成,则返回 true。
 voidshutdown()
          启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
 List<Runnable>shutdownNow()
          试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
<T> Future<T>
submit(Callable<T> task)
          提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
 Future<?>submit(Runnable task)
          提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
<T> Future<T>
submit(Runnable task, T result)
          提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
 

更详细的参考JDK API文档。

submit方法是对 Executor接口execute方法的更好的封装,建议使用submit方法。


三、ScheduleExecutorService类

在上面的5个方法中,后面2个方法的返回值都是一个ScheduleExecutorService对象。ScheduleExecutorService代表可在指定延迟或周期性执行线程任务的线程池。

ScheduleExecutorService类是ExecutorService类的子类。所以,它里面也有直接提交任务的submit方法,并且新增了一些延迟任务处理的方法:

方法摘要
<V> ScheduledFuture<V>
schedule(Callable<V> callable, long delay, TimeUnit unit)
          创建并执行在给定延迟后启用的 ScheduledFuture。
 ScheduledFuture<?>schedule(Runnable command, long delay, TimeUnit unit)
          创建并执行在给定延迟后启用的一次性操作。
 ScheduledFuture<?>scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
          创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推。
 ScheduledFuture<?>scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
          创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。
 


下面看看线程池的简单使用:


1、固定大小的线程池:

[java] view plain copy
  1. package com.tao.test;  
  2.   
  3. import java.util.concurrent.ExecutorService;  
  4. import java.util.concurrent.Executors;  
  5.   
  6. public class PoolTest {  
  7.     public static void main(String[] args) {  
  8.         ExecutorService pool=Executors.newFixedThreadPool(5);//创建一个固定大小为5的线程池  
  9.         for(int i=0;i<7;i++){  
  10.             pool.submit(new MyThread());  
  11.         }  
  12.         pool.shutdown();  
  13.     }  
  14. }  
  15. class MyThread extends Thread{  
  16.     @Override  
  17.     public void run() {  
  18.             System.out.println(Thread.currentThread().getName()+"正在执行。。。");  
  19.     }  
  20. }  
输出结果:
[java] view plain copy
  1. pool-1-thread-1正在执行。。。  
  2. pool-1-thread-3正在执行。。。  
  3. pool-1-thread-2正在执行。。。  
  4. pool-1-thread-4正在执行。。。  
  5. pool-1-thread-4正在执行。。。  
  6. pool-1-thread-5正在执行。。。  
  7. pool-1-thread-1正在执行。。。  
可以看到虽然我们呢创建了7个MyThread线程对象,但是由于受线程池的大小限制,只是开启了5个线程,这样就减少了并发线程的数量。

2、单任务线程池:

[java] view plain copy
  1. public class PoolTest {  
  2.     public static void main(String[] args) {  
  3.         ExecutorService pool=Executors.newSingleThreadExecutor();//创建一个单线程池  
  4.         for(int i=0;i<7;i++){  
  5.             pool.submit(new MyThread());  
  6.         }  
  7.         pool.shutdown();  
  8.     }  
  9. }  

输出结果:
[java] view plain copy
  1. pool-1-thread-1正在执行。。。  
  2. pool-1-thread-1正在执行。。。  
  3. pool-1-thread-1正在执行。。。  
  4. pool-1-thread-1正在执行。。。  
  5. pool-1-thread-1正在执行。。。  
  6. pool-1-thread-1正在执行。。。  
  7. pool-1-thread-1正在执行。。。  

可以看到,线程池只开启了一个线程。


3、创建可变尺寸的线程池

[java] view plain copy
  1. public class PoolTest {  
  2.     public static void main(String[] args) {  
  3.         ExecutorService pool=Executors.newCachedThreadPool();  
  4.         for(int i=0;i<5;i++){  
  5.             pool.submit(new MyThread());  
  6.         }  
  7.         pool.shutdown();  
  8.     }  
  9. }  

看输出结果:
[java] view plain copy
  1. pool-1-thread-1正在执行。。。  
  2. pool-1-thread-3正在执行。。。  
  3. pool-1-thread-2正在执行。。。  
  4. pool-1-thread-4正在执行。。。  
  5. pool-1-thread-5正在执行。。。  

可以看到,我们没有限制线程池的大小,但是它会根据需求而创建线程。


4、延迟线程池

[java] view plain copy
  1. public class PoolTest {  
  2.     public static void main(String[] args) {  
  3.         ScheduledExecutorService pool=Executors.newScheduledThreadPool(6);  
  4.         for(int i=0;i<4;i++){  
  5.             pool.submit(new MyThread());  
  6.         }  
  7.           
  8.         pool.schedule(new MyThread(), 1000, TimeUnit.MILLISECONDS);  
  9.         pool.schedule(new MyThread(), 1000, TimeUnit.MILLISECONDS);  
  10.         pool.shutdown();  
  11.     }  
  12. }  
输出结果:
[java] view plain copy
  1. pool-1-thread-1正在执行。。。  
  2. pool-1-thread-3正在执行。。。  
  3. pool-1-thread-2正在执行。。。  
  4. pool-1-thread-4正在执行。。。  
  5. pool-1-thread-6正在执行。。。  
  6. pool-1-thread-1正在执行。。。  
可以明显看到,最后两个线程不是立即执行,而是延迟了1秒在执行的。


5、单任务延迟线程池

[java] view plain copy
  1. public class PoolTest {  
  2.     public static void main(String[] args) {  
  3.         ScheduledExecutorService pool=Executors.newSingleThreadScheduledExecutor();  
  4.         for(int i=0;i<4;i++){  
  5.             pool.submit(new MyThread());  
  6.         }  
  7.           
  8.         pool.schedule(new MyThread(), 1000, TimeUnit.MILLISECONDS);  
  9.         pool.schedule(new MyThread(), 1000, TimeUnit.MILLISECONDS);  
  10.         pool.shutdown();  
  11.     }  
  12. }  


上面我们使用的是JDK帮我封装好的线程池,我们也可以自己定义线程池,查看源码,我们发现,Excutors里面的获得线程的静态方法,内部都是调用ThreadPoolExecutor的构造方法。比如:

[java] view plain copy
  1. public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {  
  2.     return new ThreadPoolExecutor(nThreads, nThreads,  
  3.                                   0L, TimeUnit.MILLISECONDS,  
  4.                                   new LinkedBlockingQueue<Runnable>(),  
  5.                                   threadFactory);  
  6. }  
可以看到,它是通过调用ThreadPoolExecutor的构造方法来返回一个线程池的。所以,我们也可以自己手动的调用ThreadPoolExecutor的各种构造方法,来定义自己的线程池规则,不过一般情况下,使用自带的线程池就够了,不需要自己来实现。


【Unity Animation 2D】从零到一:骨骼绑定与IK动画实战指南 本文详细介绍了Unity中2D骨骼绑定与IK动画的实战流程,从角色素材准备、骨骼系统创建到权重绘制和IK设置,逐步指导开发者掌握2D动画制作技巧。通过反向动力学(IK)技术,实现更自然的角色动画效果,适用于游戏开发和动画制作。 阅读详情

相关推荐

AFSim 2.9实战指南:从入门到精通的中文教程

本文是AFSim 2.9的实战指南,提供从零开始的中文教程。内容涵盖仿真环境搭建、实体行为控制、脚本编写,到传感器、武器系统集成与复杂想定构建,最后讲解数据记录与结果分析方法,帮助用户快速掌握这一强大的军事仿真框架。

weixin_29281941的博客 944

NO.17 JAVA中创建线程池的五种方法

ThreadPoolExecutor类提供了4种构造方法,可根据需要来自定义一个线程池。

qq_54252121的博客 6772

【逆强化学习-1】学徒学习(Apprenticeship Learning)

逆强化学习算法1:学徒学习。算法原理+算法步骤+代码+仿真:一个基于gym的小车上山的仿真。附赠学徒学习+Q-Table及学徒学习+DQN的全套代码。

体会编程语言独到的美 7494

线程池应用_定时执行任务

线程池应用_定时执行任务

QRLYLETITBE的博客 272

别再只调OpenCV参数了!手把手教你用Python bm3d库搞定图像去噪(附完整代码与效果对比)

本文详细介绍了BM3D算法在图像去噪中的高级应用,通过Python bm3d库实现超越OpenCV传统方法的去噪效果。文章包含完整代码示例、参数调优技巧及工程化应用场景,帮助开发者掌握这一被称为'传统方法天花板'的技术,显著提升图像信噪比和细节保留能力。

weixin_28362173的博客 366

【TC3xx芯片】TC3xx芯片UCB详解

TC3xx芯片UCB详解

qq_36056498的博客 1万+

JAVA线程池创建的几种方式,有案例很细!!!(持续更新中)

池(Pool),可以把它理解为一个容器,里面装着各种我们所需要的资源,我们需要资源的时候去这个容器里面拿,而不需要每次使用的时候去创建,从而达到一个复用的效果提高资源可利用率。

骑自行车的小黄 4923

【Davinci开发】:CS接口创建及连接

AUTOSAR SWC之间添加CS-port :详细讲解step

2527

Java线程池的创建和使用

什么是线程池? 线程池通俗的讲就是在程序启动时创建好若干个线程,供程序去调度和使用,当程序需要使用线程时不再需要去频繁的创建和销毁线程,而可以去线程池中获取空闲的线程直接使用,当使用完后线程进入空闲状态并非直接销毁线程。从JDK1.5开始,JAVA API的java.util.concurrent包下提供了Executors供开发人员方便的进行不同类型线程池的创建。 为什么使用线程池? 减小线程频繁创建和销毁对系统资源的消耗 提高系统响应速度,当系统需要使用线程时直接从池中获取 线程池可以根据实际情况进行

qq_39769154的博客 885

基于V7-690T FPGA纯逻辑实现NVMe SSD盘的读写(不使用软核)

a.NVMe的Admin CQ与Admin SQ命令放在Host内存中;因此SQ的64B要用FPGA的DDR或开一个bram空间存放,同理NVME写到HOST的CQ命令也需要存放在FPGA的DDR或一个bram空间,host收到NVME传来的MSI/MSI-X中断后,去CQ存放空间取CQ指令;b. 发送identify命令后,需要发送tial doorbell通知NVME;(发送CNS01h获取4096字节的固件信息等;发送CNS02h获取1024字节的namaspace list)

宝沐熙的博客 835

SAP UI5 主题设置全解析:从启动参数到运行时切换、跨域白名单与事件监听

SAP UI5主题体系深度解析:从配置到切换的完整指南 摘要:SAP UI5主题机制远不止CSS换肤,其工程化实践涵盖启动配置、运行时API切换、跨库路径映射及安全管控等关键环节。通过bootstrap标签或URL参数设置初始主题,运行时可用Theming.setTheme无刷新切换。自定义主题需配置theme-roots路径,跨域加载需声明sap-allowed-theme-origins白名单。主题切换完成后会触发applied事件,适合执行视觉同步操作。该体系支持多品牌适配、集中式主题管理,在Fior

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 326

java 创建线程的三种方式、创建线程池的四种方式

概要: java创建线程的三种方式: 继承Thread类创建线程类 实现Runnable接口 通过Callable和Future创建线程 java创建线程池的四种方式: newCachedThreadPool 创建一个可缓存的线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收,则新建线程 newFixedThread...

SmileTimLi的博客 4万+

AI人工智能代理工作流 AI Agent WorkFlow:在股票市场预测中的应用

AI人工智能代理工作流 AI Agent WorkFlow:在股票市场预测中的应用 作者:禅与计算机程序设计艺术 / Zen and the Art of Computer Programming 关键词: AI Agent, W

AI天才研究院 859

Java多线程(四)、线程池(转)

Java多线程(四)、线程池 分类: javaSE综合知识点 2012-09-19 17:46 3943人阅读 评论(1) 收藏 举报 系统启动一个新线程的成本是比较高的,因为它涉及到与操作系统的交互。在这种情况下,使用线程池可以很好的提供性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池。 与数据库连接池类似的是,线程池在系...

weixin_30516243的博客 73

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

(2.1.2.4)Java多线程(四)、线程池

文章目录一、new Thread的弊端二、 线程池的优势三、ThreadPoolExecutor3.1 ThreadPoolExecutor方法3.2 线程池的种类3.2.1 FixedThreadPool 可重用固定线程数3.2.2 CachedThreadPool 无限线程数3.1.3 SingleThreadExecutor 单线程化3.2.4 ScheduledThreadPool 定时周...

JAVA成长之路 343

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Java 多线程:彻底搞懂线程池

熟悉Java多线程编程的同学都知道,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了。

孙强 Jimmy 的博客 20万+

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Java多线程案例之线程池

介绍线程池的原理和简单实现, 进一步提高并发编程的效率.

trong_ 的烂笔头 6123

Java多线程、锁、线程池详解

通过本文的介绍,我们深入了解了Java中的多线程、锁机制、线程池的原理和应用。多线程可以提高程序的执行效率,但同时也带来了线程安全的问题。锁机制可以解决线程安全问题,而线程池则可以提高线程的复用率,减少线程创建和销毁的开销。理解这些概念的原理和应用可以帮助开发者编写高效、可靠的并发程序。希望本文能够帮助大家更好地理解和掌握Java中的多线程、锁和线程池,提升编程水平。

weixin_67825126的博客 2136

java多线程和线程池

目录 零、java线程理解 0.1 两种线程模型 0.1.1 用户级线程 ULT 0.1.2 内核级线程 KLT——JAVA虚拟机使用的线程模型(KLT) 0.2 java线程与系统内核线程 0.3 线程池的意义 0.4 线程 0.4.1线程五种状态 0.4.2 高并发下,线程池如何保证线程安全 0.4.3 多线程的使用场景 0.4.4 多线程的创建方式 0.4.4 多线程的停止 0.4.5控制多线程的运行顺序——join方法 一、线程池基本概念和使用示例 1.1 基本...

一直走,不要回头 8846

【java】java多线程及线程池详解

java多线程及线程池面试题

酷酷的馫博客 1万+

Java多线程——线程池

本文详细介绍了关于java线程池的相关知识点,主打一个详细面面俱到!

qq_51774011的博客 4783

【Java篇】 1.CompletableFuture使用线程池进行异步多线程处理

多线程编程是提升程序性能和响应速度的关键手段之一, Java 提供了多种方式来实现并发处理,从早期的Thread类到后来的Executor框架,Java 8 引入了,结合线程池(ThreadPool)使用,不仅简化了多线程的编写,还大大提高了代码的可读性和可维护性。相比传统的多线程方式,ThreadPool的组合为开发者提供了更高层次的抽象,保留了灵活性,又降低了复杂性。

yanqingyu000的博客 5891
上一篇: C语言函数传递指针参数的问题
下一篇: Spring中@Component的作用
TuxedoLinux
博客等级 码龄9年 268粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值