掘金 后端 ( ) • 2024-06-26 14:34

在Java中,java.util.concurrent.Executors工具类提供了四个静态工厂方法来创建不同特性的线程池,它们分别是:

1. FixedThreadPool

  • ExecutorService newFixedThreadPool(int nThreads)
  • 特点:创建一个定长的线程池,包含固定数量的核心线程,且所有线程均是核心线程。当线程池中的线程都在运行时,新提交的任务将会进入无界的工作队列中等待执行。如果线程池中的某个线程由于异常结束,那么线程池会再新建一个线程来替代。此线程池保证任何时候池中线程数不超过设定值,适用于处理大量短生命周期的任务,能有效控制系统资源。
  ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            fixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(index);
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。可参考PreloadDataCache。

2. CachedThreadPool

  • ExecutorService newCachedThreadPool()
  • 特点:创建一个可缓存的线程池,线程池根据需要自动创建或销毁线程。如果线程池中的线程数量超过了处理任务所需要的线程数量,那么多余的空闲线程将在一段时间后被终止并回收;当需要执行新的任务时,如果线程池中有空闲线程则复用,如果没有则创建新线程。这意味着此类线程池大小几乎没有限制,适合处理大量短耗时且突发性强的任务,但可能导致线程数量过多,需要注意系统的资源限制。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            try {
                Thread.sleep(index * 1000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(index);
                }
            });
        }

线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

3. SingleThreadExecutor

  • ExecutorService newSingleThreadExecutor()
  • 特点:创建一个只有一个工作线程的线程池,所有提交的任务在这个线程中按照先入先出的顺序执行。实际上,这是一个特殊的固定线程池,保证同一时间只有一个任务被执行,常用于需要串行执行任务的场景。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
    final int index = i;
    singleThreadExecutor.execute(new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println(index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}

结果依次输出,相当于顺序执行各个任务。
现行大多数GUI程序都是单线程的。Android中单线程可用于数据库操作,文件操作,应用批量安装,应用批量删除等不适合并发但可能IO阻塞性及影响UI线程响应的操作。

4. ScheduledThreadPool

  • ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
  • 特点:创建一个定长的线程池,支持定时及周期性任务执行。它允许延时或者定期地执行任务,并且能够调度多个定时任务。相比FixedThreadPool,ScheduledThreadPool多了定时任务的功能,线程池内的线程数也可以动态调整,但核心线程不会被回收。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
    @Override
    public void run() {
        System.out.println("delay 3 seconds");
    }
}, 3, TimeUnit.SECONDS);

表示延迟3秒执行。
定期执行示例代码如下:

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("delay 1 seconds, and excute every 3 seconds");
    }
}, 1, 3, TimeUnit.SECONDS);

表示延迟1秒后每3秒执行一次。
ScheduledExecutorService比Timer更安全,功能更强大

5. ThreadPoolTaskExecutor (Spring框架)

ThreadPoolTaskExecutor 是Spring框架对Java原生线程池API进行封装后的组件,它基于java.util.concurrent.ThreadPoolExecutor,并添加了一些Spring特有的功能特性,使得在Spring应用中使用线程池更为方便和灵活。

ThreadPoolTaskExecutor的主要特点和配置项包括:

  1. 核心线程数(corePoolSize):线程池的基本大小。
  2. 最大线程数(maxPoolSize):线程池所能容纳的最大线程数。
  3. 空闲线程存活时间(keepAliveSeconds):超过核心线程数的线程,在空闲多久后会被终止。
  4. 队列容量(queueCapacity):阻塞队列的大小,当线程池中所有线程都忙碌时,新提交的任务将放入队列等待执行。
  5. 线程前缀名称(threadNamePrefix):设置线程的命名前缀,方便识别和调试。
  6. 线程工厂(threadFactory):可以自定义线程创建规则。
  7. 拒绝策略(RejectedExecutionHandler):当队列和线程池都无法接受新任务时,定义如何处理被拒绝的任务。

使用ThreadPoolTaskExecutor可以在Spring配置文件中通过bean的方式进行配置,然后在代码中注入该bean来执行异步任务,这样可以更好地与Spring容器整合,实现任务的异步处理和调度。例如:

log.info("线程执行");
//多线程异步执行
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("createUserNoticeLog-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
ThreadPoolExecutor pushExecutorService = executor.getThreadPoolExecutor();
pushExecutorService.submit(() -> {
  //相关程序逻辑 ,比如发送用户短信
  sms.sned("15011462646","msg text")
  log.info("批量发送短信线程执行");
});


原文链接 https://www.hanyuanhun.cn | https://node.hanyuanhun.cn

本文使用 文章同步助手 同步