开卷有益 union/substact/intersect/difference

Java线程池处理子线程超时问题

  起因

  近几天,某个正常运行了近两个月的项目,单日处理请求条数锐减,排查日志发现如下异常:

Mon Apr 29 18:12:01 CST 2019, org.apache.hadoop.hbase.client.RpcRetryingCaller@34f04eb2, java.io.IOException: java.io.IOException: Could not seek StoreFileScanner[HFileScanner for reader reader=hdfs://Ucluster5/hbase/data/default/video_search_shot/5402a6d8800f28541d456a50367cc757/d/b98d69cfc81f4903a3ddb94e95114454, compression=none, cacheConf=CacheConfig:enabled [cacheDataOnRead=true] [cacheDataOnWrite=false] [cacheIndexesOnWrite=false] [cacheBloomsOnWrite=false] [cacheEvictOnClose=false] [cacheCompressed=false], firstKey=8bfc17007695e96ae27e049a11b42792:11.000_0.133/d:dhash128/1554703137033/Put, lastKey=8e00dfe4801a80988f7fe7944120317b:14.000_1.000/d:video/1554768240786/Put, avgKeyLen=65, avgValueLen=398, entries=356358, length=168414223, cur=null] to key 8de584f3a3f112d2cbe581f1f8e30588:0.000_1.000/d:/LATEST_TIMESTAMP/DeleteFamily/vlen=0/mvcc=0
at org.apache.hadoop.hbase.regionserver.StoreFileScanner.seek(StoreFileScanner.java:157)
at org.apache.hadoop.hbase.regionserver.StoreScanner.<init>(StoreScanner.java:168)
at org.apache.hadoop.hbase.regionserver.HStore.getScanner(HStore.java:1648)
at org.apache.hadoop.hbase.regionserver.HRegion$RegionScannerImpl.<init>(HRegion.java:3513)
at org.apache.hadoop.hbase.regionserver.HRegion.instantiateRegionScanner(HRegion.java:1816)
at org.apache.hadoop.hbase.regionserver.HRegion.getScanner(HRegion.java:1808)
at org.apache.hadoop.hbase.regionserver.HRegion.getScanner(HRegion.java:1785)
at org.apache.hadoop.hbase.regionserver.HRegion.get(HRegion.java:4538)
at org.apache.hadoop.hbase.regionserver.HRegion.get(HRegion.java:4513)
at org.apache.hadoop.hbase.regionserver.HRegionServer.get(HRegionServer.java:2780)
at org.apache.hadoop.hbase.protobuf.generated.ClientProtos$ClientService$2.callBlockingMethod(ClientProtos.java:26925)
at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:2141)
at org.apache.hadoop.hbase.ipc.RpcServer$Handler.run(RpcServer.java:1844)
Caused by: java.io.IOException: Failed to read compressed block at 159280276, onDiskSizeWithoutHeader=67484, preReadHeaderSize=33, header.length=33, header bytes: DATABLK*\x00\x01\x07:\x00\x01\x07&\x00\x00\x00\x00\x07\x97\x02\xD9\x01\x00\x00@\x00\x00\x01\x07G
at org.apache.hadoop.hbase.io.hfile.HFileBlock$FSReaderV2.readBlockDataInternal(HFileBlock.java:1495)
at org.apache.hadoop.hbase.io.hfile.HFileBlock$FSReaderV2.readBlockData(HFileBlock.java:1358)
at org.apache.hadoop.hbase.io.hfile.HFileReaderV2.readBlock(HFileReaderV2.java:335)
at org.apache.hadoop.hbase.io.hfile.HFileBlockIndex$BlockIndexReader.loadDataBlockWithScanInfo(HFileBlockIndex.java:253)
at org.apache.hadoop.hbase.io.hfile.HFileReaderV2$AbstractScannerV2.seekTo(HFileReaderV2.java:474)
at org.apache.hadoop.hbase.io.hfile.HFileReaderV2$AbstractScannerV2.seekTo(HFileReaderV2.java:495)
at org.apache.hadoop.hbase.regionserver.StoreFileScanner.seekAtOrAfter(StoreFileScanner.java:225)
at org.apache.hadoop.hbase.regionserver.StoreFileScanner.seek(StoreFileScanner.java:145)
... 12 more
Caused by: java.io.IOException: Invalid HFile block magic: \x00\x00\x00\x00\x00\x00\x00\x00
at org.apache.hadoop.hbase.io.hfile.BlockType.parse(BlockType.java:154)
at org.apache.hadoop.hbase.io.hfile.BlockType.read(BlockType.java:165)
at org.apache.hadoop.hbase.io.hfile.HFileBlock.<init>(HFileBlock.java:258)
at org.apache.hadoop.hbase.io.hfile.HFileBlock$FSReaderV2.readBlockDataInternal(HFileBlock.java:1492)
... 19 more

  协调大数据与运维部门,最终定位错误为Hadoop集群某个节点磁盘坏块,随后运维更换磁盘,速度略微提升,该异常仍然存在(最终排查确认仍有其他节点磁盘坏块,全部更换后问题解决).这就造成一个问题,业务代码操作video_search_shot这张表时,将因此阻塞,时长达到数分钟.考虑到磁盘坏块客观存在,数据库连接超时过久,故设置线程超时时间成了必然选择.

  线程超时解决方案

  常用的线程超时处理方法有很多,例如Thread.join(long timeout)/Future.get(long timeout,TimeUnit unit)/ExecutorService的超时方法...实际应用中,偏爱使用第二种 Future.get(long timeout,TimeUnit unit),因为其相对来说更灵活,关键是该类更熟悉,而且相对于针对线程池的超时处理,该方案处理粒度更小,便于掌控.

  实操

  既然选择使用Future的get方法去处理线程超时问题,这里就需要考虑线程池子线程的处理时机,在调用get方法时,子线程应处于未执行状态,否则超时处理就没有意义.故排除ExecutorService.invokeAll(Collection<? extends Callable<T> tasks>)/ExecutorService.invokeAny(Collection<? extends Callable<T> tasks>)及二者对应的线程池超时方法.这时往线程池提交子线程的选择就剩下了ExecutorService.submit(....),其次,需要处理的异常,首先是TimeoutException,其次是,InterruptedIOException,因为将调用Future.cancel(boolean mayInterruptIfRunning)方法中断子线程.

  代码

        ExecutorService exec = Executors.newFixedThreadPool(4);
List<Future<Boolean>> futures = new ArrayList<>();
Callable<Integer> task;
for (int i = 0;i<4;i++) {
task = () -> {
TimeUnit.SECONDS.sleep(50);
return true;
};
Future<Boolean> futureNow = exec.submit(task);
futures.add(futureNow);
} for (Future<Integer> future :
futures) { try {
Integer intRes = future.get(2000, TimeUnit.MILLISECONDS);
System.out.println("result : " + intRes);
} catch (InterruptedException ex) {
System.out.println("子线程被中断 ");
} catch (ExecutionException e) {
System.out.println("子线程执行出错");
} catch (TimeoutException e) {
System.out.println("处理超时");
} finally {
future.cancel(true); // 中断子线程
}
}
exec.shutdown();

Java多线程处理某个线程超时的问题的更多相关文章

  1. java中异步多线程超时导致的服务异常

    在项目中为了提高大并发量时的性能稳定性,经常会使用到线程池来做多线程异步操作,多线程有2种,一种是实现runnable接口,这种没有返回值,一种是实现Callable接口,这种有返回值. 当其中一个线 ...

  2. 【Java基础】线程和并发机制

    前言 在Java中,线程是一个很关键的名词,也是很高频使用的一种资源.那么它的概念是什么呢,是如何定义的,用法又有哪些呢?为何说Android里只有一个主线程呢,什么是工作线程呢.线程又存在并发,并发 ...

  3. Java总结之线程(1)

    java线程是很重要的一项,所以作为java程序员必须要掌握的. 理解java线程必须先理解线程在java中的生命周期.. 1.java线程生命周期 1.new  创建一个线程  java中创建线程有 ...

  4. 第9章 Java中的线程池 第10章 Exector框架

    与新建线程池相比线程池的优点 线程池的分类 ThreadPoolExector参数.执行过程.存储方式 阻塞队列 拒绝策略 10.1 Exector框架简介 10.1.1 Executor框架的两级调 ...

  5. Java并发之线程转储

    一.java线程转储 java的线程转储可以被定义为JVM中在某一个给定的时刻运行的所有线程的快照.一个线程转储可能包含一个单独的线程或者多个线程.在多线程环境中,比如J2EE应用服务器,将会有许多线 ...

  6. Java并发之线程池ThreadPoolExecutor源码分析学习

    线程池学习 以下所有内容以及源码分析都是基于JDK1.8的,请知悉. 我写博客就真的比较没有顺序了,这可能跟我的学习方式有关,我自己也觉得这样挺不好的,但是没办法说服自己去改变,所以也只能这样想到什么 ...

  7. Java中创建线程的三种方式以及区别

    在java中如果要创建线程的话,一般有3种方法: 继承Thread类: 实现Runnable接口: 使用Callable和Future创建线程. 1. 继承Thread类 继承Thread类的话,必须 ...

  8. Java多线程(五) —— 线程并发库之锁机制

    参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...

  9. Java并发之——线程池

    一. 线程池介绍 1.1 简介 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡 ...

随机推荐

  1. (详细)华为荣耀V10 BKL-AL00的USB调试模式在哪里打开的步骤

    每当我们使用pc连接安卓手机的时候,如果手机没有开启Usb开发者调试模式,pc则无法成功检测到我们的手机,有时我们使用的一些功能比较强的的app比如以前我们使用的一个app引号精灵,老版本就需要开启U ...

  2. matlab练习程序(对应点集配准的四元数法)

    这个算是ICP算法中的一个关键步骤,单独拿出来看一下. 算法流程如下: 1.首先得到同名点集P和X. 2.计算P和X的均值up和ux. 3.由P和X构造协方差矩阵sigma. 4.由协方差矩阵sigm ...

  3. Ehcache入门经典:第一篇

    ehcache主要是轻量级的缓存实现 ehcache.xml <?xml version="1.0" encoding="UTF-8"?> < ...

  4. Mysql 获取表设计查询语句

    SELECT COLUMN_NAME 列名, COLUMN_TYPE 数据类型, DATA_TYPE 字段类型, CHARACTER_MAXIMUM_LENGTH 长度, IS_NULLABLE 是否 ...

  5. git取消跟踪已版本控制的文件

    git 不再追踪文件改动 git update-index --assume-unchanged filePath git 恢复追踪文件改动 git update-index —no-assume-u ...

  6. hashCode()方法对HashMap的性能影响

    HashMap的put()方法会比较key的hash值,key的hash值获取方式如下: //HashMap的put方法 public V put(K key, V value) { return p ...

  7. spring异步执行报异常No qualifying bean of type 'org.springframework.core.task.TaskExecutor' available

    最近观察项目运行日志的时候突然发现了一个异常, [2018-04-03 10:49:07] 100.0.1.246 http-nio-8080-exec-9 DEBUG org.springframe ...

  8. 根据List集合中的对象属性排序

    首先创建一个Student对象,里面有三个属性,分别是int类型,String类型,Date类型 package com.sinoway.cisp.test; import java.text.Sim ...

  9. CSS---内外边距

    1.内外边距含义 内边距是div边框内的距离.背景色会覆盖内边距,内边距会使宽高变大. 外边距是div边框外的距离.背景色不会覆盖外边距 内外边距都会撑高父元素,外边距会提高div与div之间的距离 ...

  10. 常见设计模式 (python代码实现)

    1.创建型模式 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对 ...