线程池创建方式详解

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的ThreadFactory创建一个新线程。

线程池的创建主要依赖于java.util.concurrent包下的ExecutorService和Executors类。最近面试问到了这块,所以这篇文章我们将详细介绍几种常见的线程池创建方式。

FixedThreadPool

FixedThreadPool是一种固定大小的线程池。它的核心线程数和最大线程数都是创建时指定的数值 ,且不会变化。就算空闲,也不会回收线程,除非设置了allowCoreThreadTimeOut。

举个栗子:我们创建一个固定大小为5的线程池,并提交10个任务。由于线程池的大小固定为5,因此这5个线程会并发执行,而剩下的任务会等待前面的任务完成后再执行。

代码如下:

java 复制代码
	import java.util.concurrent.ExecutorService;  

	import java.util.concurrent.Executors;  

	  

	public class FixedThreadPoolDemo {  

	    public static void main(String[] args) {  

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

	        ExecutorService executorService = Executors.newFixedThreadPool(5);  

	  

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

	            Runnable worker = new WorkerThread("" + i);  

	            executorService.execute(worker);  // 执行任务  

	        }  

	        executorService.shutdown();  // 关闭线程池  

	        while (!executorService.isTerminated()) {  

	        }  

	        System.out.println("所有任务已完成");  

	    }  

	}  

	  

	class WorkerThread implements Runnable {  

	    private String command;  

	  

	    public WorkerThread(String s) {  

	        this.command = s;  

	    }  

	  

	    @Override  

	    public void run() {  

	        System.out.println(Thread.currentThread().getName() + " 开始. 命令 = " + command);  

	        processCommand();  

	        System.out.println(Thread.currentThread().getName() + " 结束.");  

	    }  

	  

	    private void processCommand() {  

	        try {  

	            Thread.sleep(5000);  

	        } catch (InterruptedException e) {  

	            e.printStackTrace();  

	        }  

	    }  

	}

CachedThreadPool

CachedThreadPool是一种缓存线程池,它的线程数量是不定的,可以说是几乎无限的。当提交一个任务时,如果线程池中有空闲线程,则立即执行;如果没有,则创建一个新线程执行。当线程空闲超过60秒,则自动回收。

举个栗子:

java 复制代码
	import java.util.concurrent.ExecutorService;  

	import java.util.concurrent.Executors;  

	  

	public class CachedThreadPoolDemo {  

	    public static void main(String[] args) {  

	        // 创建一个可缓存的线程池  

	        ExecutorService executorService = Executors.newCachedThreadPool();  

	  

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

	            Runnable worker = new WorkerThread("" + i);  

	            executorService.execute(worker);  // 执行任务  

	        }  

	        executorService.shutdown();  // 关闭线程池  

	        while (!executorService.isTerminated()) {  

	        }  

	        System.out.println("所有任务已完成");  

	    }  

	}

CachedThreadPool`适合执行大量的耗时较少的任务,如Web服务器。

SingleThreadExecutor

SingleThreadExecutor是一个单线程的Executor,它使用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。

java 复制代码
	import java.util.concurrent.ExecutorService;  

	import java.util.concurrent.Executors;  

	  

	public class SingleThreadExecutorDemo {  

	    public static void main(String[] args) {  

	        // 创建一个单线程的线程池  

	        ExecutorService executorService = Executors.newSingleThreadExecutor();  

	  

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

	            Runnable worker = new WorkerThread("" + i);  

	            executorService.execute(worker);  // 执行任务  

	        }  

	        executorService.shutdown();  // 关闭线程池  

	        while (!executorService.isTerminated()) {  

	        }  

	        System.out.println("所有任务已完成");  

	    }  

	}

在SingleThreadExecutor中,由于只有一个线程,因此任务会按照提交的顺序一个接一个地执行,不会出现并发的情况。

ScheduledThreadPool

ScheduledThreadPool 是 Java 并发包 java.util.concurrent 中提供的一个线程池实现,它用于在给定的延迟后运行命令,或者定期地执行命令。ScheduledThreadPool 的主要特点是能够处理需要定时执行或周期性执行的任务。

举个栗子:

java 复制代码
	import java.util.concurrent.Executors;  

	import java.util.concurrent.ScheduledExecutorService;  

	import java.util.concurrent.TimeUnit;  

	  

	public class ScheduledThreadPoolDemo {  

	    public static void main(String[] args) {  

	        // 创建一个ScheduledThreadPool,包含3个核心线程  

	        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);  

	  

	        // 提交一个Runnable任务,在延迟2秒后执行  

	        scheduledExecutorService.schedule(new RunnableTask("一次性任务"), 2, TimeUnit.SECONDS);  

	  

	        // 提交一个Runnable任务,初始延迟2秒,之后每隔1秒执行一次  

	        scheduledExecutorService.scheduleAtFixedRate(new RunnableTask("周期性任务"), 2, 1, TimeUnit.SECONDS);  

	  

	        // 通常我们需要在程序结束时关闭线程池  

	        // scheduledExecutorService.shutdown();  

	    }  

	  

	    static class RunnableTask implements Runnable {  

	        private String command;  

	  

	        public RunnableTask(String command) {  

	            this.command = command;  

	        }  

	  

	        @Override  

	        public void run() {  

	            System.out.println(Thread.currentThread().getName() + " 开始执行命令: " + command + " at " + System.currentTimeMillis());  

	        }  

	    }  

	}

我们创建了一个 ScheduledThreadPool,它包含3个核心线程。然后,我们提交了两个任务:

  1. 一个是一次性任务,它在提交后的2秒后开始执行。
  2. 另一个是周期性任务,它在提交后的2秒开始执行,然后每隔1秒执行一次。

除了以上的用法 ,ScheduledExecutorService 提供了几个用于定时执行任务的方法:

  • schedule(Runnable command, long delay, TimeUnit unit):在给定延迟后运行命令一次。
  • scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):初始延迟后开始首次执行,然后随后每隔固定周期执行一次。
  • scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit):初始延迟后开始首次执行,然后每次执行完毕后等待固定延迟再次执行。

如果任务执行过程中抛出异常,那么 ScheduledThreadPool 会停止该任务的后续执行,但不会停止线程池本身或其他任务的执行。如果需要处理任务执行中的异常,可以在任务内部进行捕获和处理。

以上就是创建线程池的几种方式,本篇文章到此结束,谢谢大家的观看!

相关推荐
CCblandy1 小时前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构
我是人✓1 小时前
SpringBoot项目的五种创建方式
java·spring boot·后端
念念清晰3 小时前
000-OpenJDK17 源码构建:MacOS环境(M芯片)
java·后端
来福猿3 小时前
SpringCloud Config 源码分析:配置拉取、刷新与多环境管理
后端·spring·spring cloud
IT_陈寒5 小时前
React组件莫名重渲染?你可能忘了这个小细节
前端·人工智能·后端
用户9888321871745 小时前
给 .NET 网络调用设定“预算”:用 CancellationTokenSource.CancelAfter 处理超时取消
后端
清风儿3296 小时前
一块不会说话的电表,把我们折腾了半个月
后端
预知同行6 小时前
深入解析 MoE 混合专家模型:从 Router 到 All-to-All 的架构全景与生产实践
后端·架构
upala6 小时前
【仓颉语言入门 · 第二篇 第 8 课】
后端
weiwin1236 小时前
MAF 入门(8):多模态实战——让 Agent 看懂图片、处理混合内容
人工智能·后端