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

您所在的位置:网站首页 线程的创建方式 JAVA线程池创建的几种方式,有案例很细!!!(持续更新中)

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

2024-07-01 19:45:12| 来源: 网络整理| 查看: 265

一、引言: 什么是池?

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

线程池的概念

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。简单点理解就是在需要使用多线程执行任务的时候不需要进行线程的创建,而是把任务提交到线程池中由线程池按照一定的规则处理。

简单线程池Demo public static void main(String[] args) { // 创建一个固定大小的线程池,大小为2 ExecutorService executorService = Executors.newFixedThreadPool(2); // 提交3个任务给线程池 for (int i = 0; i < 3; i++) { Runnable task = new Task(i); executorService.submit(task); } // 所有任务执行完毕,关闭线程池 CSDN 骑电动车的小黄 executorService.shutdown(); } static class Task implements Runnable { private int taskId; public Task(int taskId) { this.taskId = taskId; } @Override public void run() { System.out.println("Task " + taskId + " 执行中..."); try { // 暂停, Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task " + taskId + " 执行完毕"); } } 执行结果 Task 1 执行中... Task 0 执行中... Task 0 执行完毕 Task 1 执行完毕 Task 2 执行中... Task 2 执行完毕 二、创建线程池的几种方式 1、Executors类创建线程池

java.util.concurrent.Executors java自带的创建、管理线程池工具,可以简化线程池的创建和管理过程,提高性能和代码的可读性。提供了四种创建方法:

1.1:newFixedThreadPool(int nThreads)

使用 newFixedThreadPool 创建一个固定为 nThreads 大小的线程池,假如我们创建一个大小为2的线程池提交了3个任务过去,那么就会有2个任务同时被执行,后面的任务会等前面的任务执行完按顺序执行。newFixedThreadPool创建线程的案例 ——> 简单线程池Demo

使用场景:

提交的任务数量可控的情况下,能具体的预预估出任务数,并希望限制并发执行的任务数。资源限制,系统资源有限使用合理固定大小的线程池可以防止资源浪费的情况简化管理,只需要配置固定大小的线程数即可使用。 1.2:newCachedThreadPool()

创建可以缓存的线程池,有任务提交到线程池时如果有空闲的线程可用则立即使用空闲线程执行任务,如果没有空闲的线程可用就会创建一个新的线程执行任务,当空闲线程闲置一段时间(默认是60秒)之后还未被使用,那么就会进行销毁操作。

使用场景:

不确定任务数量或者任务频率较高的情况下,并且期望能自动调整线程数量适应任务数量的变化时并发低、任务量较少,系统之间相对独立并发量比较低想降低对线程池的维护成本异步任务、短期任务例如IO型的任务可以相对较好的利用系统资源,减少维护成本又能提交任务效率

使用案例:

public static void main(String[] args) { // 创建可缓存的线程池 ExecutorService executorService = Executors.newCachedThreadPool(); // 提交任务给线程池 CSDN 骑电动车的小黄 for (int i = 0; i < 5; i++) { final int taskNumber = i; executorService.execute(new Runnable() { @Override public void run() { System.out.println("Task " + taskNumber + " 执行中..."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task " + taskNumber + " 执行完毕"); } }); } // 关闭线程池 executorService.shutdown(); }

执行结果:

Task 0 执行中... Task 1 执行中... Task 2 执行中... Task 3 执行中... Task 4 执行中... Task 3 执行完毕 Task 0 执行完毕 Task 4 执行完毕 Task 2 执行完毕 Task 1 执行完毕 1.3:newSingleThreadExecutor()

创建一个单线程的线程池,它只会使用一个线程执行任务,可以保证任务的执行顺序。

使用场景:

通常使用在任务需要按顺序执行但又不影响主线程执行,且任务之间存在依赖关系或者需要共享资源,保证任务在同一线程内执行避免线程安全问题。

使用案例:

public static void main(String[] args) { System.out.println("开始执行"); // 创建单线程的线程池 ExecutorService executorService = Executors.newSingleThreadExecutor(); // 提交任务给线程池 CSDN 骑电动车的小黄 for (int i = 0; i < 5; i++) { final int taskNumber = i; executorService.execute(new Runnable() { @Override public void run() { System.out.println("Task " + taskNumber + " 执行中..."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task " + taskNumber + " 执行完毕"); } }); } // 关闭线程池 executorService.shutdown(); System.out.println("主线程执行完毕,等待线程池任务执行。"); }

执行结果:

1.4:newScheduledThreadPool(int corePoolSize)

提供了任务调度功能与Spring提供的定时任务注解@Scheduled有相似之处,用于执行延迟性任务、周期性任务,corePoolSize指定线程池的核心线程数,除核心线程数之外当任务数过多时会根据需要创建额外的临时线程来执行任务,临时线程数最多不超过核心线程数。

案例:

public static void main(String[] args) { // 创建具有固定核心线程数的线程池 CSDN 骑电动车的小黄 ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2); // 延迟任务 executorService.schedule(new Runnable() { @Override public void run() { System.out.println("延迟任务开始执行...."); } }, 3, TimeUnit.SECONDS); // 周期性任务,每隔1秒执行一次 executorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("周期性任务开始执行...."); } }, 0, 1, TimeUnit.SECONDS); // 等待一段时间后关闭线程池 try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } executorService.shutdown(); System.out.println("主线程执行完毕。。。"); }

执行结果:

需要注意的是周期性任务的任务时间是由上一次任务的结束时间来进行计算的,而不是上一次任务的开始时间,比如我们在周期执行内暂停2秒,那么就会出现以下情况,上一次执行完之后马上开始下一次任务。

2、ForkJoinPool

java.util.concurrent.ForkJoinPool 也是java并发库中提供的一个线程池的实现,适用于可拆分的任务,提供了三种创建线程池的方法:

ForkJoinPool()ForkJoinPool(int parallelism)ForkJoinPool.commonPool()

通常使用 ForkJoinPool.commonPool()  进行创建,它可以获取一个共享的 ForkJoinPool 实例,该实例由 JVM 自动管理并在需要时进行共享和重用,这个共享的线程池一般与处理器核心数保持一致。

案例:

public static void main(String[] args) { // 获取共享的 ForkJoinPool 实例 CSDN 骑电动车的小黄 ForkJoinPool commonPool = ForkJoinPool.commonPool(); // 创建一个可拆分的任务 RecursiveTask task = new RecursiveTask() { @Override protected Integer compute() { // 任务的计算逻辑 Integer i = 1; System.out.println("执行了 ==>" + i); return i; } }; // 提交任务到 commonPool 并获取结果 Integer result = commonPool.invoke(task); result = result + 100; System.out.println("返回结果: " + result); }

执行结果:

3、ThreadPoolExecutor( 常用 )

java.util.concurrent.ThreadPoolExecutor 是 java 用于管理线程池和创建线程池的类,提供了比较灵活的方式来控制线程池中的数量、任务队列、拒绝策略,工作中使用频率也是最高的。

ThreadPoolExecutor(),中可自定义配置线程池七个参数,使用情况可以参考 ==>  线程池的七个配置参数,很细!!!_骑电动车的小黄的博客-CSDN博客

使用案例:

public class PoolTest { public static void main(String[] args) { // 创建一个阻塞队列,用于存放等待执行的任务 BlockingQueue queue = new LinkedBlockingQueue(10); // 创建自定义的线程池,设置核心线程数、最大线程数、等待时间、时间单位、任务队列等参数 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES, queue); // 提交任务给线程池,使用 execute() 方法提交 for (int i = 0; i < 20; i++) { Runnable task = new MyTask(i); executor.execute(task); } // 关闭线程池 executor.shutdown(); } } class MyTask implements Runnable { private final int taskId; public MyTask(int taskId) { this.taskId = taskId; } @Override public void run() { System.out.println("Task ID : " + taskId + " 执行 " + Thread.currentThread().getName()); } }

执行结果:

Task ID : 1 执行 pool-1-thread-2 Task ID : 3 执行 pool-1-thread-4 Task ID : 5 执行 pool-1-thread-4 Task ID : 0 执行 pool-1-thread-1 Task ID : 2 执行 pool-1-thread-3 Task ID : 9 执行 pool-1-thread-3 Task ID : 10 执行 pool-1-thread-3 Task ID : 8 执行 pool-1-thread-1 Task ID : 7 执行 pool-1-thread-4 Task ID : 16 执行 pool-1-thread-7 Task ID : 14 执行 pool-1-thread-7 Task ID : 6 执行 pool-1-thread-2 Task ID : 17 执行 pool-1-thread-8 Task ID : 12 执行 pool-1-thread-1 Task ID : 13 执行 pool-1-thread-4 Task ID : 11 执行 pool-1-thread-3 Task ID : 4 执行 pool-1-thread-5 Task ID : 15 执行 pool-1-thread-6 Task ID : 19 执行 pool-1-thread-10 Task ID : 18 执行 pool-1-thread-9 4、第三方工具包

比如使用 guava 包创建线程池,首先引入 guava 包。

com.google.guava guava 30.1-jre

创建线程池、提交任务

public class PoolTest { public static void main(String[] args) { // 使用 ThreadFactoryBuilder 创建自定义线程工厂 ThreadFactoryBuilder threadFactoryBuilder = new ThreadFactoryBuilder() .setNameFormat("线程-%d") .setDaemon(true); ExecutorService executorService = Executors.newFixedThreadPool(5, threadFactoryBuilder.build()); // 提交任务给线程池 for (int i = 0; i < 10; i++) { Runnable task = new MyTask(i); executorService.execute(task); } // 关闭线程池 executorService.shutdown(); } } class MyTask implements Runnable { private final int taskId; public MyTask(int taskId) { this.taskId = taskId; } @Override public void run() { System.out.println("Task ID : " + taskId + " 执行 " + Thread.currentThread().getName()); } }

执行结果

Task ID : 0 执行 线程-0 Task ID : 2 执行 线程-2 Task ID : 1 执行 线程-1 Task ID : 3 执行 线程-3 Task ID : 4 执行 线程-4 Task ID : 5 执行 线程-1 Task ID : 6 执行 线程-0 Task ID : 8 执行 线程-1 Task ID : 7 执行 线程-3 Task ID : 9 执行 线程-0



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭