高并发的情况下,最大限度防线程池数据丢失和保证数据可靠性,主要办法SynchronousQueue+CallerRunsPolicy+ApplicationShutdownHook+记录offset+记录详情到日志表
//当核心线程数等于最大线程数keepAliveTime是失效的
//SynchronousQueue零容量队列,即无等待队列
//线程拒绝策略CallerRunsPolicy:核心线程和临时线程都在工作,且达到最大线程数,且队列已满,新加任务会在父线程执行,阻塞父线程。
SynchronousQueue+CallerRunsPolicy可以防止数据丢失,因为任务要么被线程池线程消费。要么线程池达到最大线程数且全部在工作就会被父线程消费阻塞父线程以防止提交新的任务。
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(maxConcurrentThreadNum, maxConcurrentThreadNum * 2, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy());
以上线程池配置配上ApplicationShutdownHook 可最大限度保证数据不丢失,可以在关闭钩子里修改一个全局共享且线程安全的变量的值,用来告诉所有用到线程池的地方停止接受新任务,然后等待30秒(目的是让已经提交的任务执行完,这个时间可以适当调整) ,然后关闭程序
//ApplicationShutdownHook使用示例
Runtime.getRuntime().addShutdownHook(new Thread(()->System.out.println("程序正常关闭")));
记录offset ,可以防止数据丢失和重复
记录详情到日志表, 虽然会因为IO操作导致性能降低,但牺一丢丢性能增加了可靠性,可以防止数据丢失和重复
,且在排查问题和对账时起到关键性作用