业务中的场景:接口对外开放,对方调接口,推数据过来,前期可能对方接入的业务方比较少,开启的线程也少,所以对我们这边的时间不做要求,所以我们接口是处理了大批数据入库,存云,处理下来整个代码走完要好几分钟,再给对方响应,但是前几天对方突然在微信群里限制了接口的超时时间,超时了之后对方就默认该批数据处理失败,会重新推送这一批数据,导致我们生产库中出现了重复推过来的数据.所以就需要开启另外一条线程执行业务代码,接口的主线程校验完数据之后直接返回响应,以达到超时要求.
可优化的点:这里由于之前同事的代码的线程池都是随用随创建:
ExecutorService executor = Executors.newFixedThreadPool(20);
之后可能会创建多个线程池,所以自己加了个单例的线程池,程序启动则加载,节省了重复创建线程池所消耗的资源,需要线程直接从创建好的线程池取就可以了.
单例的线程池:
/**
* @author zsc
* @ClassName GlobalThreadPool
* @date 2019/11/7 16:07
*/
@Log4j2
public final class GlobalThreadPool {
/**
* 核心线程数
*/
private static final int CORE_POOL_SIZE = 30;
/**
* 最大线程数
*/
private static final int MAXIMUM_POOL_SIZE = 60;
/**
* 空闲线程的存活时间
*/
private static final int KEEP_ALIVE_TIME = 1000;
/**
* 任务队列的大小
*/
private static final int BLOCKING_QUEUE_SIZE = 1000;
private GlobalThreadPool() {
}
/**
* 饿汉初始化
*/
private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(BLOCKING_QUEUE_SIZE),
new ThreadFactoryBuilder().setNameFormat("global-thread-pool-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy());
public static ThreadPoolExecutor getExecutor() {
return EXECUTOR;
}
}
这里采用的任务拒绝策略为由调用该线程处执行该任务.
调用处的代码:
param.setStatus("1");
bwDataExchangeDAO.insertBwData(param);
//遍历数据,拿到输入流,解析输入流
log.info("当前线程为:" + Thread.currentThread().getName());
//开启另一条线程去执行数据解析,以防超时
GlobalThreadPool.getExecutor().submit(() ->
resolveData(param));
} else {
bwDataExchangeDAO.insertBwData(param);
}
主线程调用线程池开启完线程之后就直接把任务扔给这个线程去处理,直接rtn就完事了.
下面看测试代码:
@Test
public void test11(){
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
GlobalThreadPool.getExecutor().submit(new Runnable() {
@Override
public void run() {
System.out.println("当前线程为:" + Thread.currentThread().getName());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//计数减一
countDownLatch.countDown();
}
}
});
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("5个线程已执行完毕");
}
控制台的输出:
当前线程为:global-thread-pool-0
当前线程为:global-thread-pool-1
当前线程为:global-thread-pool-2
当前线程为:global-thread-pool-3
当前线程为:global-thread-pool-4
5个线程已执行完毕