场景,有两个接口分别会接收两个数据,如果其中一个数据校验失败,那么另一个数据也要删掉。
由于是两个独立的数据源,没法做事务的回滚。( 这两个数据源是来自canal的监听得到的)。
因此考虑的方案就是,当校验不通过的时候,通过异步的方式,去起一个线程去删掉另一个接口过来的任务,但是这两个数据过来会有延时几秒,因此在另一个线程里面,先休眠3秒在执行删除。
因此考虑用一个线程池,防止校验不通过的数据过多导致创建过多的线程让系统出现问题。
线程池的参数:
1.第一个参数是核心线程数 2个
2.第二个参数是最大线程数10个
3.第三个参数是空闲线程存活时间60秒
4.第四个参数是时间单位 秒
5.线程任务队列,设置成了100个任务, 有界队列,如果队列满了,就会创建新的线程 ,最大不超过10个。 如果还有任务,就会执行拒绝策略
6.线程工厂,继承了ThreadFactor ,用于创建线程,设置了线程名称 ,方便后续出问题排查
7.拒绝策略,这里的策略是直接放弃任务,并打印日志。
new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(100),
(Runnable r) -> {
Thread t = new Thread(r);
t.setName("删除校验失败的对帐单关联的保险数据线程");
log.info("启动"+t.getName());
return new Thread(r);
}, (Runnable r, ThreadPoolExecutor executor) -> {
log.error("已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了");
});
拒绝策略,默认的几种拒绝策略有 1.直接抛异常,2.忽视掉,3.丢掉最老的任务,4.让当初线程执行
这里我们选择忽视掉并打印日志。
得用单例模式,保证线程池的唯一,不至于每一次都创建一个新的线程池。不然这个线程池就没意义了。
懒汉模式,通过静态内部类实现,因类只要用的时候才会被加载,且只加载一次,且加载过程是加锁的(jvm实现)
public class CheckAccountThreadPoolUtil {
//静态方法获取对象
public static ExecutorService getWorkPoolUtil() {
//调用内部静态类的静态方法获取对象
//这个时候触发内部类的加载 也就是只有在用的时候才会加载,懒汉模式
return Helper.getInstance();
}
//内部类加载之后
private static class Helper {
//静态字段 在类加载的时候被初始化 且只初始化一次
private static ExecutorService instance=new ExecutorService(){}.... ;
//获取对象
public static ExecutorService getInstance() {
return instance;
}
}
单例和非单例的验证
非单例
public class CheckAccountThreadPoolUtil {
public static ExecutorService getWorkPoolUtil() {
return Helper.getInstance();
}
private static class Helper {
private static ExecutorService instance;
public static ExecutorService getInstance() {
if (instance!=null){
return instance;
}
instance = new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(100),
(Runnable r) -> {
Thread t = new Thread(r);
t.setName("删除校验失败的对帐单关联的保险数据线程");
log.info("启动"+t.getName());
return new Thread(r);
}, (Runnable r, ThreadPoolExecutor executor) -> {
log.error("已超出最大任务数,那么校验不通过的对账单数据,狗日的系统出问题了,删不过来了");
});
return instance;
}
}
}
十个线程同时获取如下
public static void main(String[] args) throws InterruptedException, IOException {
//同时启动10个 看是否是单例
CountDownLatch countDownLatch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
log.info("进入等待");
countDownLatch.countDown();
try {
//在这个节点等待countDownLatch减少到0
countDownLatch.await();
} catch (InterruptedException e) {
e.pri