赞
踩
默认情况下,线程池创建后,池中是没有线程的,需要提交任务才会创建线程,也可以通过
preStartAllCoreThreads()
设置,在线程池创建时就初始化所有核心线程。
一般我们都是使用配置文件定义线程池属性,如下:
#异步线程池配置
async:
executor:
thread:
core_pool_size: 20
max_pool_size: 20
queue_capacity: 100
keep_alive_seconds: 60
thread_name_prefix: AsyncExecutorThread-
线程池配置类:
package com.utour.config; 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//启用异步任务 public class AsyncConfig { @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.keep_alive_seconds}") private int keepAliveSeconds; @Value("${async.executor.thread.thread_name_prefix}") private String threadNamePrefix; @Bean(name = "asyncExecutor") public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(corePoolSize);//核心线程数 executor.setMaxPoolSize(maxPoolSize);//最大线程数 executor.setQueueCapacity(queueCapacity);//线程池队列容量 executor.setKeepAliveSeconds(keepAliveSeconds);//空闲的线程多久后被销毁,只对超出corePoolSize的线程起作用(如果核心线程数和最大线程数一样,一般不配置这个属性) executor.setAllowCoreThreadTimeOut(true);//核心线程在规定时间内会被回收,默认为false executor.setThreadNamePrefix(threadNamePrefix);//线程池中线程的名称前缀 //rejection-policy:饱和策略,当pool已经达到max size的时候,如何处理新任务? //CallerRuns:不在新线程中执行任务,而是由调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize();//初始化 return executor; } }
使用@Async
注解,想要使其生效,必须满足以下条件:
在 @SpringBootApplication 启动类或者多线程配置类上加注解@EnableAsync,启用异步任务
异步方法上使用@Async
,返回值为 void 或 Future。
切记切记切记 ,异步方法和调用方法一定要写在不同类中,写在同一个类中是没有效果的,建议建一个 AsyncService 异步处理类,类上加@Service
注解,专门处理异步方法。
Executors.newFixedThreadPool采用的就是无界队列,spring的线程池也是采用无界队列。
当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理任务。
任务类型不同,设置方式不一样。
最佳线程数 = (线程等待时间/线程CPU时间 + 1)* CPU核数
一个CountDownLatch实例是不能重复使用的,可以重复使用的是CyclicBarrier。
import com.example.zzz.service.AsyncTaskService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @RunWith(SpringRunner.class) @SpringBootTest public class ZzzApplicationTests { @Resource(name = "asyncExecutor") private Executor taskExecutor;//这个是springboot的线程池配置类ThreadPoolTaskExecutor @Test public void contextLoads() { CountDownLatch latch = new CountDownLatch(50);//这个初始化计数要和线程数一样 for (int i = 0; i < 50; i++) { final int j = i; taskExecutor.execute(new Runnable() { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + "---" + j); } catch (Exception e) { e.printStackTrace(); } finally { latch.countDown();//不管线程是否异常都需要计数器减少 } } }); } try{ latch.await(20L, TimeUnit.SECONDS);//保证之前的所有线程都执行完,才会执行下面的 System.out.println("the race end"); }catch(Exception e){ e.printStackTrace(); } System.out.println("bingo"); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。