小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
问题场景
线程异步批量写Hbase文件,正常的情况百万级别数据量,批量写Hbase在10s以内可以写完,但是线上kerberos认证有点问题,导致Hbase put 的操作一直重试超时,Hbase 重试30几次, 耗费半个小时以上,导致业务人员很难快速感知到任务执行失败。如果在并发量很大的情况下,线程执行时间过程,可能会导致线程池耗尽系统宕机, 或者频繁的GC等等异常。那么这种线程任务执行超时的问题如何解决呢?
解决方案
线程池 + CountDownLatch 解决线程执行超时的问题。 模拟一下业务中的场景, 创建一个固定大小的线程池, 这边场景比较明确,可以直接用newFixedThreadPool, 阿里编码规范上明确不建议用这个,但是我们如果了解这些线程池的原理,在合适的场景下还是可以用的。 下面创建一个线程池, 执行任务run,休眠60秒种, 创建一个 CountDownLatch 计数器, 线程任务执行完之后减一, 但是我们设置计数器线程等待的时间为59秒, 所以当线程到59秒的时候, 任务线程还没有执行完,直接关闭线程, 然后抛一个异常。
@Test
public void test() {
ExecutorService executorService = Executors.newFixedThreadPool(1);
final CountDownLatch countDownLatch = new CountDownLatch(1);
executorService.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(60 * 1000 );
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
}
});
try {
countDownLatch.await(59, TimeUnit.SECONDS);
executorService.shutdown();
if(countDownLatch.getCount()> 0){
System.out.println("线程执行超时。。。");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}