线程池任务统计应用

本文介绍了一种自定义线程池的方法,通过继承ThreadPoolExecutor并覆盖其计数功能,实现了任务计数的重置。示例代码展示了如何创建自定义线程池并使用它来执行多个任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ThreadPoolExecutor没有重置计数的功能,简单实现一下

public class NewThreadPoolExecutor extends ThreadPoolExecutor {

	private long tempCompletedTaskCount;

	private long tempTaskCount;

	public NewThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
	}

	public NewThreadPoolExecutor(int nThreads) {
		super(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
	}

	public long getCompletedTaskCount() {
		return super.getCompletedTaskCount() - tempCompletedTaskCount;
	}

	public long getTaskCount() {
		return super.getTaskCount() - tempTaskCount;
	}

	public void resetTaskCount() {
		if (super.getCompletedTaskCount() == super.getTaskCount()) {
			tempCompletedTaskCount = super.getCompletedTaskCount();
			tempTaskCount = super.getTaskCount();
		}
	}
}

public class Test {
	private static NewThreadPoolExecutor executorService = new NewThreadPoolExecutor(5);
	
	public static void main(String[] args) throws Exception {
		final Future<Integer> f1 = executorService.submit(new Callable<Integer>() {
			@Override
			public Integer call() throws Exception {
				TimeUnit.SECONDS.sleep(2);
				int temp = 0;
				while (temp++ < 30)
					System.out.println("F1-" + temp + Thread.currentThread().getName());
				return Integer.valueOf(temp);
			}
		});
		final Future<Integer> f2 = executorService.submit(new Callable<Integer>() {
			@Override
			public Integer call() throws Exception {
				int temp = 0;
				while (temp++ < 30)
					System.out.println("F2-" + temp + Thread.currentThread().getName());
				;
				return Integer.valueOf(temp);
			}
		});
		final Future<Integer> f3 = executorService.submit(new Callable<Integer>() {
			@Override
			public Integer call() throws Exception {
				int temp = 0;
				while (temp++ < 30)
					System.out.println("F3-" + temp + Thread.currentThread().getName());
				;
				return Integer.valueOf(temp);
			}
		});
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName());
					System.out.println(f1.get() + f2.get() + f3.get());
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (ExecutionException e) {
					e.printStackTrace();
				}
			}
		});

		System.out.println("【线程活跃数】" + executorService.getActiveCount());
		System.out.println("【总任务数】" + executorService.getTaskCount());
		System.out.println("【已完成任务数】" + executorService.getCompletedTaskCount());
		TimeUnit.SECONDS.sleep(8);
		System.out.println("【线程活跃数】" + executorService.getActiveCount());
		System.out.println("【总任务数】" + executorService.getTaskCount());
		System.out.println("【已完成任务数】" + executorService.getCompletedTaskCount());

		// 重新计数
		executorService.resetTaskCount();
		final Future<Integer> f4 = executorService.submit(new Callable<Integer>() {
			@Override
			public Integer call() throws Exception {
				TimeUnit.SECONDS.sleep(3);
				int temp = 0;
				while (temp++ < 30)
					System.out.println("F4-" + temp + Thread.currentThread().getName());
				;
				return Integer.valueOf(temp);
			}
		});
		f4.get();
		System.out.println("【线程活跃数】" + executorService.getActiveCount());
		System.out.println("【总任务数】" + executorService.getTaskCount());
		System.out.println("【已完成任务数】" + executorService.getCompletedTaskCount());
	}
}


<think>我们正在讨论线程池应用方式和最佳实践。用户之前的问题是关于规则引擎部署流程,但当前问题转向了线程池的使用。根据提供的引用,我们需要结合引用[1]和引用[2]来回答。引用[1]提供了Java线程池的概述和类型,引用[2]则提到了项目中如何合理使用线程池,特别提到了ThreadPoolExecutor的推荐使用。用户需求:了解项目中线程池应用方式和最佳实践。因此,回答应涵盖:1.线程池的核心优势(避免频繁创建销毁线程,资源复用,控制并发规模等)2.线程池的常见类型(根据引用[1]的六种类型,重点说明项目中常用的)3.如何创建和配置线程池(特别是ThreadPoolExecutor,因为引用[2]推荐使用)4.最佳实践(包括参数设置、任务队列选择、拒绝策略、监控等)同时,注意回答结构清晰,逐步展开。另外,根据系统指令,需要生成相关问题,并在引用处添加引用标识。注意:用户提供的引用中有两个引用标记[^1]和[^2],我们在回答中引用它们时也要对应使用。由于用户要求使用中文,并且要符合LaTeX格式要求(但本问题中可能涉及数学公式较少,所以重点在代码块和结构化展示)。计划结构:1.线程池在项目中的核心价值2.线程池类型选择指南(结合引用[1])3.线程池的创建与配置(重点ThreadPoolExecutor,引用[2])4.最佳实践与常见陷阱5.总结6.相关问题注意:引用标识的添加要自然,例如在提到某种线程池类型时,如果信息来源于引用[1],则在句子末尾添加[^1];在提到使用ThreadPoolExecutor时,如果信息来源于引用[2],则添加[^2]。</think>### 项目中线程池应用指南与最佳实践 线程池是管理多线程任务的核心组件,能显著提升系统性能和资源利用率。以下是项目中的关键应用方式和实践要点: --- #### 一、线程池选型策略(根据场景选择) | 线程池类型 | 适用场景 | 特点说明 | |----------------------------|----------------------------------|-----------------------------| | **FixedThreadPool** | 稳定并发场景(如HTTP请求处理) | 固定线程数,避免资源耗尽[^1] | | **CachedThreadPool** | 短时异步任务(如日志记录) | 自动扩容,空闲线程回收[^1] | | **ScheduledThreadPool** | 定时任务(如数据同步) | 支持延迟/周期性执行[^2] | | **SingleThreadExecutor** | 需顺序执行的任务(如消息队列消费)| 单线程保障顺序性[^1] | | **ThreadPoolExecutor** | **复杂定制场景(推荐)** | 完全参数可控,灵活性最强[^2] | > ⚠️ 注意:`Executors`快速创建线程池可能隐藏风险(如`CachedThreadPool`无界队列导致OOM),**生产环境优先使用`ThreadPoolExecutor`手动配置**[^2]。 --- #### 二、ThreadPoolExecutor 核心参数配置 ```java ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, // 核心线程数 (常驻) maximumPoolSize, // 最大线程数 (突发流量缓冲) keepAliveTime, // 非核心线程空闲存活时间 TimeUnit.MILLISECONDS, // 时间单位 new LinkedBlockingQueue<>(queueCapacity), // 任务队列 new CustomRejectedExecutionHandler() // 拒绝策略 ); ``` 1. **参数计算公式**: - **核心线程数**:$corePoolSize = CPU核心数 \times (1 + 等待时间/计算时间)$ (IO密集型建议 $2N_{cpu}$,计算密集型建议 $N_{cpu}+1$) - **队列容量**:根据系统容忍延迟设置,建议 $queueCapacity = corePoolSize \times 2$ 2. **拒绝策略选择**: | 策略类 | 行为 | |---------------------------|------------------------------| | `AbortPolicy` | 直接抛异常(默认) | | `CallerRunsPolicy` | 由提交任务的线程执行 | | `DiscardOldestPolicy` | 丢弃队列最老任务 | | `DiscardPolicy` | 静默丢弃新任务 | > 推荐使用`CallerRunsPolicy`避免任务丢失,同时降低提交速度[^2]。 --- #### 三、最佳实践与避坑指南 1. **资源隔离**: - 关键业务使用独立线程池(如支付与日志分离) - 避免共享全局线程池导致级联故障 2. **监控与调优**: ```java // 获取运行时指标 executor.getActiveCount(); // 活动线程数 executor.getQueue().size(); // 队列积压量 executor.getCompletedTaskCount(); // 已完成任务 ``` - 配置监控告警:线程池饱和度 > 80% 时扩容 - 使用`Micrometer`导出指标到Prometheus[^1] 3. **生命周期管理**: ```java // 优雅关闭 executor.shutdown(); if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); // 强制关闭 } ``` 4. **异常处理**: - 任务内捕获所有异常,避免线程无声退出 - 使用`Thread.UncaughtExceptionHandler`全局处理 --- #### 四、典型应用场景 1. **高并发请求处理** ```java // Web服务请求异步化 @PostMapping("/order") public CompletableFuture<Order> createOrder() { return CompletableFuture.supplyAsync(() -> orderService.process(), ioExecutor); } ``` 2. **批量任务并行化** ```java // 并行处理数据批次 List<CompletableFuture<Void>> futures = dataList.stream() .map(batch -> CompletableFuture.runAsync(() -> processBatch(batch), batchExecutor)) .collect(Collectors.toList()); CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); ``` 3. **定时调度任务** ```java // 每天凌晨执行统计 scheduledExecutor.scheduleAtFixedRate( () -> generateDailyReport(), 0, // 初始延迟 24, // 周期 TimeUnit.HOURS ); ``` --- ### 总结 线程池应用核心原则: 1. **资源可控**:通过`ThreadPoolExecutor`精准配置参数[^2] 2. **场景适配**:IO密集型增大线程数,计算密集型控制线程数[^1] 3. **防御编程**:设队列上限 + 合理拒绝策略 + 完备监控 4. **生命周期管理**:优雅关闭保障任务完整性 > 遵循以上实践,线程池可提升吞吐量30%~300%(视场景而定),同时避免OOM、线程泄漏等生产事故。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值