前言
1.之前简单的说过使用ThreadPoolExecutor创建线程池是优于使用Executors创建线程池,链接:ThreadPoolExecutor手动创建线程池优于Executors类
2.下面内容中会涉及到线程池的拒绝策略,这里可以阅读其他作者的文章,链接拒绝策略
一、线程池工具类
自定义实现JAVA线程池的线程工厂类——ThreadFactory:Java提供了ThreadFactory接口,用于创建你自己的线程对象工厂,可以设置线程名称、优先级等属性。(这里我只设置了线程名称,其他的大家自己探索)
public class ThreadPoolUtils {
public static ExecutorService createExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, int queueSize, String name) {
return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
new LinkedBlockingQueue<>(queueSize), new NamedThreadFactory(name),
new ThreadPoolExecutor.CallerRunsPolicy());
}
public static ExecutorService singleExecutor(String name, RejectedExecutionHandler handler) {
return new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(2),
new NamedThreadFactory(name), handler);
}
/**
* 自定义实现JAVA线程池的线程工厂类
* 自定义具有描述意义的线程名称。如果使用默认的ThreadFactory,它给线程起名字大概规律就是pool-m-thread-n,但是当你分析一个thread dump时,看着这样的名字就很难知道线程的目的。所以使用一个有描述意义的线程名称是分析追踪问题的关键。
* 设置线程是否是守护线程,默认的ThreadFactory总是提交非守护线程
* 设置线程优先级,默认ThreadFactory总是提交的一般优先级线程
*/
public static class NamedThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
public NamedThreadFactory(String prefix) {
this.namePrefix = prefix + "-";
}
@Override
public Thread newThread(Runnable r) {
String name = namePrefix + nextId.getAndIncrement();
return new Thread(null, r, name);
}
}
}
二、使用工具类中的线程池
private ExecutorService sigleThreadExecutor = ThreadPoolUtils.singleExecutor("test",new ThreadPoolExecutor.CallerRunsPolicy());
public void test(){
List<String> list = new ArrayList<>();
// 记录单个任务的执行次数
CountDownLatch countDownLatch = new CountDownLatch(list .size());
for(String str : list){
sigleThreadExecutor.execute(() ->{
//这里编写要处理的方法
System.out.println(str);
// 任务个数 - 1, 直至为0时唤醒await()
countDownLatch.countDown();
});
}
// 让当前线程处于阻塞状态,直到锁存器计数为零
countDownLatch.await();
}
三、使用注入的方式创建并使用线程池
//启动类
@SpringBootApplication
public class EtlServiceApplication {
public static void main(final String[] args) {
SpringApplication.run(EtlServiceApplication.class, args);
}
//启动类中注入线程池服务
@Bean
public ExecutorService executorService(){
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("sch-pool-%d").build();
ExecutorService pool = new ThreadPoolExecutor(20, 500,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(4096), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
return pool;
}
}
//使用类中注入
@Autowired
private ExecutorService executorService;
//实用类中使用
//我们通常使用两种方式来创建线程:集成Thread类和实现Runnable接口
executorService.execute(Runnable runnable);