java如何创建线程池(3种方式)

java如何创建线程池(3种方式)

在生产环境中,我们不用Thread来启动线程任务,都通过线程池的方式来进行启动,我们来看看常用的线程池的使用方式


9c70d276ddee62bd98b6e0dbcb12609.png

1.利用Executors静态工厂类创建线程池(不推荐)

  • newSingleThreadExecutor创建“单线程化线程池”
  • newFixedThreadPool创建“固定数量的线程池”
  • newCachedThreadPool创建“可缓存线程池”
  • newScheduledThreadPool创建“可调度线程池”
public class MainDemo {
    public static void main(String[] args) {
        
        //ExecutorService executorService = Executors.newSingleThreadExecutor();
        //ExecutorService executorService = Executors.newFixedThreadPool(100);
        //ExecutorService executorService = Executors.newCachedThreadPool();
        
        //executorService.submit(new TaskRunnable());
        
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        scheduledExecutorService.submit(new TaskRunnable());

    }

2.通过ThreadPoolExecutor标准创建线程池(推荐)

1.先创建线程池管理类

package com.leo.springbootmultithreadbasic.threadpool;

import com.leo.springbootmultithreadbasic.common.CommonConstant;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;


public class ThreadPoolManage {

    /**
     * 线程池的阻塞队列:
     * LinkedBlockingQueue、SynchronousQueue、ArrayBlockingQueue、LinkedTransferQueue、PriorityBlockingQueue
     */
    private LinkedBlockingQueue<Runnable> linkedBlockingQueue = new LinkedBlockingQueue<>(2);

    /**
     * Thread factory
     */
    private ThreadFactory threadFactory = new MyThreadFactory2("ThreadFactory");

    public ThreadPoolExecutor threadPoolExecutor =
            new ThreadPoolExecutor(CommonConstant.CORE_POOL_SIZE,
                                   CommonConstant.MAXIMUM_POOL_SIZE,
                                   CommonConstant.KEEP_ALIVE_TIME,
                                   CommonConstant.TIME_UNIT,
                                   linkedBlockingQueue,
                                    threadFactory);

    public void addTask(Runnable task) {
        threadPoolExecutor.execute(task);
    }
}

2.通过线程池管理执行线程任务

public class MainDemo {
    public static void main(String[] args) {
        ThreadPoolManage threadPoolManage = new ThreadPoolManage();
        threadPoolManage.addTask(new TaskRunnable());
    }
}

3.SpringBoot利用ThreadPoolTaskExecutor创建线程池

ThreadPoolTaskExecutor是spring进行封装ThreadPoolExecutor的,其本质是还是ThreadPoolExecutor,在SpringBoot框架中还是更推荐用ThreadPoolTaskExecutor创建线程池

1.由于要添加线程时进行日志的打印,我们先写一个类来继承ThreadPoolTaskExecutor

package com.wwj.component;


import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

/*
showThreadPoolInfo 方法中将任务总数、已完成数、活跃线程数,队列大小都打印出来了,然后 Override 了父类的
 execute、submit 等方法,在里面调用 showThreadPoolInfo 方法,
 这样每次有任务被提交到线程池的时候,都会将当前线程池的基本情况打印到日志中;
 */
@Slf4j
public class ThreadPoolTaskExecutorManage extends ThreadPoolTaskExecutor {

    private void showThreadPoolInfo() {
        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();

        if (null == threadPoolExecutor) {
            return;
        }

        log.info("{},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
                this.getThreadNamePrefix(),
                threadPoolExecutor.getTaskCount(),
                threadPoolExecutor.getCompletedTaskCount(),
                threadPoolExecutor.getActiveCount(),
                threadPoolExecutor.getQueue().size());
    }

    @Override
    public void execute(Runnable task) {
        this.showThreadPoolInfo();
        super.execute(task);
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        this.showThreadPoolInfo();
        super.execute(task, startTimeout);
    }

    @Override
    public Future<?> submit(Runnable task) {
        this.showThreadPoolInfo();
        return super.submit(task);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        this.showThreadPoolInfo();
        return super.submit(task);
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        this.showThreadPoolInfo();
        return super.submitListenable(task);
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        this.showThreadPoolInfo();
        return super.submitListenable(task);
    }
}

2.构建配置类

package com.wwj.config;

import com.wwj.component.ThreadPoolTaskExecutorManage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {

    @Value("${async.executor.thread.core_pool_size}")
    private int corePoolSize;
    @Value("${async.executor.thread.max_pool_size}")
    private int maxPoolSize;
    @Value("${async.executor.thread.queue_capacity}")
    private int queueCapacity;
    @Value("${async.executor.thread.name.prefix}")
    private String namePrefix;


    @Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutorManage();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(queueCapacity);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix(namePrefix);

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // AbortPolicy:该策略是线程池的默认策略。使用该策略时,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常。
        // DiscardPolicy:这个策略和AbortPolicy的slient版本,如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常。
        // DiscardOldestPolicy:这个策略从字面上也很好理解,丢弃最老的。也就是说如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列。
        //因为队列是队尾进,队头出,所以队头元素是最老的,因此每次都是移除对头元素后再尝试入队。
        // CALLER_RUNS:当队列忙了,由主线程去执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }

}

3.编写配置文件

server.port=8080

# 异步线程配置
# 配置核心线程数
async.executor.thread.core_pool_size = 2
# 配置最大线程数
async.executor.thread.max_pool_size = 2
# 配置队列大小
async.executor.thread.queue_capacity = 4
# 配置线程池中的线程的名称前缀
async.executor.thread.name.prefix = async-service-

4.利用注解进行使用

package com.wwj.service.impl;

import com.wwj.service.AsyncService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService {

    @Override
    @Async("asyncServiceExecutor")
    public void executeAsync() {
        log.info("start executeAsync");
        System.out.println("do something");
        log.info("end executeAsync");
    }
}

直接调用方法即可

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容