线程池的使用

简介: Java语言虽然内置了多线程支持,启动一个新线程非常方便,但是,创建线程需要操作系统资源(线程资源,栈空间等),频繁创建和销毁大量线程需要消耗大量时间

假设没有线程池引发的后果:


创建线程所需要的时间多少?以及线程在完成工作之后会被丢弃的事实

如果允许所有的并发请求都通过新线程来处理,那么我们没法限制系统内的并发执行线程的数量

无限制的线程可能耗尽系统资源 (如CPU时间和内存)

线程池的主要思想:


在进程开始时,创建一定数量的线程,并放到线程池中等待工作

当服务器收到请求时,线程池会唤醒池内的一个线程(如果有可用线程),并将需要服务的请求传递给它

线程完成了服务,会返回线程池中等待工作

如果线程池中没有可用线程,那么服务器会等待,直到有可用线程为止

总结:


线程池内部维护了若干个线程,没有任务的时候,这些线程都处于等待状态


如果有新任务,就分配一个空闲线程执行。如果所有线程都处于忙碌状态,新任务要么放入队列等待,要么增加一个新线程进行处理


线程池的优点:


用已有的线程服务请求比创建一个线程更快

线程池限制了任何时候可用线程的数量,对不能支持大量并发线程的系统很重要

将要执行任务从创建任务的机制中分离出来(例如,任务可以被安排在某一个时间延迟后再执行,或定期执行)

线程池内线程的数量可以通过一些因素来估算(例如,系统CPU的数量,物理内存的大小,并发客户请求数量的期望值等)


更高级的线程池架构可以根据使用模式动态调整线程池内线程的数量,这类线程池架构再系统负荷低的时候,提供比较小的线程池,从而降低内存消耗(例如Apple的大中央空调)


Java标准库提供了 ExecutorService 接口表示线程池,用法如下:


           Runnable task1 = null;

           Runnable task2 = null;

           Runnable task3 = null;

           Runnable task4 = null;

           Runnable task5 = null;

           //创建固定大小的线程池

           ExecutorService executorService=Executors.newFixedThreadPool(3);

           //提交任务

           executorService.submit(task1);

           executorService.submit(task2);

           executorService.submit(task3);

           executorService.submit(task4);

           executorService.submit(task5);

ExecutorService 只是接口,Java标准库提供的几个常用实现类有:


FixedThreadPool:线程数固定的线程池

CachedThreadPool:线程数根据任务动态调整的线程池

SingleThreadExecutor:仅单线程执行的线程池

创建这些线程池的方法都被封装到Executors这个类中,以FixedThreadPool为例:


import java.util.concurrent.*;

public class Main {

   public static void main(String[] args) {

       // 创建一个固定大小的线程池:

       ExecutorService es = Executors.newFixedThreadPool(4);

       for (int i = 0; i < 6; i++) {

           es.submit(new Task("" + i));

       }

       // 关闭线程池:

       es.shutdown();

   }

}

class Task implements Runnable {

   private final String name;

   public Task(String name) {

       this.name = name;

   }

   @Override

   public void run() {

       System.out.println("start task " + name);

       try {

           Thread.sleep(1000);

       } catch (InterruptedException e) {

       }

       System.out.println("end task " + name);

   }

}

//允许结果如下:

start task 0

start task 1

start task 2

start task 3

end task 0

start task 4

end task 1

start task 5

end task 2

end task 3

end task 4

end task 5


运行结果分析:一次性放入6个任务,由于线程池只有固定的4个线程,因此,前4个任务会同时执行,等到有线程空闲后,才会执行后面的两个任务。


线程池在程序结束的时候要关闭。使用shutdown()方法关闭线程池的时候,它会等待正在执行的任务先完成,然后再关闭。shutdownNow()会立刻停止正在执行的任务,awaitTermination()则会等待指定的时间让线程池关闭。


如果我们把线程池改为CachedThreadPool,由于这个线程池的实现会根据任务数量动态调整线程池的大小,所以6个任务可一次性全部同时执行。


如果我们想把线程池的大小限制在4~10个之间动态调整怎么办?


直接安排代码:


    int min = 4;

    int max = 10;

ExecutorService es = new ThreadPoolExecutor(min, max,

       60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());

如果我们想定时让线程跑任务怎么办?


Java标准库还提供了一个java.util.Timer类,这个类也可以定期执行任务,但是,一个Timer会对应一个Thread,所以,一个Timer只能定期执行一个任务,多个定时任务必须启动多个Timer,而一个ScheduledThreadPool就可以调度多个定时任务,所以,我们完全可以用ScheduledThreadPool取代旧的Timer


JDK提供了ExecutorService实现了线程池功能:


线程池内部维护一组线程,可以高效执行大量小任务


Executors提供了静态方法创建不同类型的ExecutorService


必须调用shutdown()关闭ExecutorService


ScheduledThreadPool可以定期调度多个任务


目录
打赏
0
0
0
0
4
分享
相关文章
使用 Haproxy + Nginx 实现高可用
Haproxy 是目前比较流行的一种集群调度工具,同类集群调度器工具有很多,如 LVS 和 Nginx。相比较而言,LVS 性能最好,但是搭建相对复杂;Nginx 的 upstream 模块虽然支持集群功能,但是对集群节点健康检查功能不强,性能没有 Haproxy 好。
968 0
使用 Haproxy + Nginx 实现高可用
os-copilot安装与多项功能测评
本文介绍了os-copilot的安装及多项功能测评。首先,通过xShell连接服务器并使用`rpm -q os-copilot`检查是否已安装,若未安装则用`yum install`命令安装。接着,配置ACCESS_KEY信息以连接阿里云服务。深入测试部分展示了-t参数用于环境健康检查、-f参数处理复杂任务、|参数解释代码等功能,还演示了编写shell脚本创建和启动Redis的便捷性。这些功能对基础运维和开发人员有较大帮助。
189 14
钉钉对话机器人实现赞踩收集
本文介绍如何通过AppFlow记录钉钉AI对话卡片的用户反馈情况。首先确保已接入钉钉AI机器人,然后分三步实现:1) 修改钉钉AI消息卡片,添加点赞按钮并配置回调参数;2) 配置钉钉卡片点赞消息接收连接流,更新卡片状态;3) 设置日志收集节点,存储用户反馈数据。完成配置后,用户可在群聊中与机器人互动,并使用点踩点赞功能,反馈数据将被有效记录和分析。
284 6
钉钉对话机器人实现赞踩收集
Python 教程之 Pandas(7)—— 遍历 Pandas DataFrame 中的行和列
Python 教程之 Pandas(7)—— 遍历 Pandas DataFrame 中的行和列
744 0
EMR管控平台全面升级:智能化助力客户实现在离线混部和降本增效
本次介绍EMR开源大数据平台2.0的最新特性,基于微服务架构,提供更稳定高效的服务。平台升级主要体现在智能化和Serverless两个方面。智能化功能利用大语言模型提升运维效率,推出一键诊断和根因分析,缩短问题定位时间。全托管弹性伸缩根据业务动态自动调整资源,提高资源利用率。即将推出的EMR on ACS产品形态支持离在线业务混部,进一步优化资源使用,帮助用户实现降本增效。
一文带你了解OSPF虚链路以及配置方法
一文带你了解OSPF虚链路以及配置方法
318 1
一文带你了解OSPF虚链路以及配置方法
深入浅出Node.js:从零开始构建RESTful API
在数字化时代的浪潮中,后端开发作为连接用户与数据的桥梁,扮演着至关重要的角色。本文将引导您步入Node.js的奇妙世界,通过实践操作,掌握如何使用这一强大的JavaScript运行时环境构建高效、可扩展的RESTful API。我们将一同探索Express框架的使用,学习如何设计API端点,处理数据请求,并实现身份验证机制,最终部署我们的成果到云服务器上。无论您是初学者还是有一定基础的开发者,这篇文章都将为您打开一扇通往后端开发深层知识的大门。
148 12
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问