SpringBoot中线程池的一些常规用法

创建线程池的常用方法

1、使用Executors进行创建

ExecutorService poo1 = Executors.newFixedThreadPool(10);
ExecutorService pool = Executors.newSingleThreadExecutor();
ExecutorService poo1 = Executors.newCachedThreadPool();
ExecutorService poo1 = Executors.newScheduledThreadPool(10);

2、通过ThreadPoolExecutor创建线程池

// threadFactory 创建线程的工厂,通常会重新指定线程名,方便debug
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("这是线程%d - ").build();

ExecutorService pool = new ThreadPoolExecutor(3, 6, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(3), threadFactory, new ThreadPoolExecutor.AbortPolicy());

以上是一个简单的实例,表示创建一个核心线程数为3,最大线程数为6,超时0s就进行回收,缓存队列容量为3,并使用AbortPolicy的拒绝策略

1、配置TaskExecutor

这里直接将线程池注入

创建ThreadPoolConfig类,注意,需标记@EnableAsync

@Configuration
@EnableAsync
public class ThreadPoolConfig {
  //其他
  
  @Bean
public Executor defaultThreadPool() {
    ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
    executor.setPoolSize(线程大小);
    executor.setThreadPriority(优先级);
    executor.setThreadNamePrefix(名称前缀);
    executor.initialize();
    return executor;
}

}

配置1、自定义配置


@Configuration
//@EnableAsync
public class ThreadPoolConfig {

    /**
     *   默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,
     *  当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
     *  当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝
     */

    /**
     * 获得Java虚拟机可用的处理器个数 + 1
     */
    private static final int THREADS = Runtime.getRuntime().availableProcessors() + 1;

    @Value("${async.executor.thread.core_pool_size:0}")
    public static int corePoolSizeConfig;
    // 核心线程池大小
    public static int corePoolSize = corePoolSizeConfig ==0 ? THREADS : corePoolSizeConfig;

    // 最大可创建的线程数
    //@Value("${async.executor.thread.max_pool_size}")
    private int maxPoolSize = 2 * THREADS;;

    // 队列最大长度
    //@Value("${async.executor.thread.queue_capacity}")
    private int queueCapacity = 1024;

    // 线程池维护线程所允许的空闲时间
    //@Value("${async.executor.thread.keep_alive_seconds}")
    private int keepAliveSeconds = 300;

    //线程池名前缀 
    //@Value("${async.executor.thread.threadNamePrefix}")
    private static final String threadNamePrefix = "Async-Service-";

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setThreadNamePrefix(threadNamePrefix);
        // 线程池对拒绝任务(无线程可用)的处理策略
        // CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
        return executor;
    }

}

4、Async调用

执行代码和任务效率比较差的时候,可以考虑使用Async进行异步调用。

注意:
1、static 方法使用@Async注解无效
2、异步方法和调用异步方法不能在同一个类里面

使用配置:

@EnableAsync
@Configuration
class TaskPoolConfig {

	@Bean("taskExecutor")
	public Executor taskExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		//设置核心线程数
		executor.setCorePoolSize(10);
		//设置最大线程数
		executor.setMaxPoolSize(20);
		//线程池所使用的缓冲队列
		executor.setQueueCapacity(200);
		 // 设置线程活跃时间(秒)
		executor.setKeepAliveSeconds(60);
	    //  线程名称前缀
		executor.setThreadNamePrefix("taskExecutor-");
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		// 等待所有任务结束后再关闭线程池
		executor.setWaitForTasksToCompleteOnShutdown(true);
		// 等待时间 (默认为0,此时立即停止),并没等待xx秒后强制停止
		executor.setAwaitTerminationSeconds(60);
		return executor;
	}
}

使用方法:

1、在Spring Boot中,我们只需要通过使用@Async注解就能简单的将原来的同步函数变为异步函数,Task类改在为如下模式:

import java.util.Random;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
publicclass Task2 {
    //定义一个随机对象.
    publicstatic Random random =new Random();
    //任务一;
    @Async
    publicvoid doTaskOne() throws Exception {
        System.out.println("开始做任务一");
        longstart = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        longend = System.currentTimeMillis();
        System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
    }
    //任务二;
    @Async
    publicvoid doTaskTwo() throws Exception {
        System.out.println("开始做任务二");
        longstart = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        longend = System.currentTimeMillis();
        System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
    }
    //任务3;
    @Async
    publicvoid doTaskThree() throws Exception {
        System.out.println("开始做任务三");
        longstart = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        longend = System.currentTimeMillis();
        System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
    }
}

3、为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync,如下所示:

@EnableAsync
publicclass App {
    //省略其它代码…
}

3、编写测试方法:

//测试task2.
@RequestMapping("/task2")
public String task2() throws Exception{
   task2.doTaskOne();
   task2.doTaskTwo();
   task2.doTaskThree();
   return"task2";
}

4、等待多个异步任务执行完应该怎么办

public class AsyncTask {

    @Async
    public Future<String> task1() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(1000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
        return new AsyncResult<String>("task1执行完毕");
    }

    @Async
    public Future<String> task2() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(2000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
        return new AsyncResult<String>("task2执行完毕");
    }
    @Async
    public Future<String> task3() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(3000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
        return new AsyncResult<String>("task3执行完毕");
    }
}

使用时:

@RestController
public class AsyncTaskController {

    @Autowired
    private AsyncTask asyncTask;

    @RequestMapping("")
    public String doTask() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Future<String> task1 = asyncTask.task1();
        Future<String> task2 = asyncTask.task2();
        Future<String> task3 = asyncTask.task3();
        String result = null;
        for (;;) {
            if(task1.isDone() && task2.isDone() && task3.isDone()) {
                // 三个任务都调用完成,退出循环等待
                break;
            }
            Thread.sleep(1000);
        }
        long currentTimeMillis1 = System.currentTimeMillis();
        result = "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms";
        return result;
    }
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注