范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

记一次使用线程池出现的问题(线程池异常)

  背景
  之前在工作中遇到一个问题,我定义了一个线程池来执行任务,程序执行结束后任务没有全部执行完。
  业务场景是这样的:由于统计业务需要,订单信息需要从主库中经过统计业务代码写入统计库。由于代码质量及历史原因,目前的重新统计接口是单线程的,粗略算了算一共有100万条订单信息,每100条的处理大约是10秒,所以理论上处理完全部信息需要28个小时,这还不算因为 mysql 中 limit 分页导致的后期查询时间以及可能出现的内存溢出导致中止统计的情况。
  基于上述的原因,以及最重要的一点:统计业务是根据订单所属的中心进行的,各个中心同时统计不会导致脏数据。所以,我计划使用线程池,为每一个中心分配一条线程去执行统计业务。业务实现// 线程工厂,用于为线程池中的每条线程命名 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("stats-pool-%d").build();  // 创建线程池,使用有界阻塞队列防止内存溢出 ExecutorService statsThreadPool = new ThreadPoolExecutor(5, 10,                 0L, TimeUnit.MILLISECONDS,                 new LinkedBlockingQueue<>(100), namedThreadFactory); // 遍历所有中心,为每一个centerId提交一条任务到线程池 statsThreadPool.submit(new StatsJob(centerId));
  在创建完线程池后,为每一个 centerId 提交一条任务到线程池。在我的预想中,由于线程池的核心线程数为5,最多5个中心同时进行统计业务,将大大缩短100万条数据的总统计时间,于是万分兴奋的我开始执行重新统计业务了。问题
  在跑了很久之后,当我查看统计进度时,我发现了一个十分诡异的问题(如下图)。蓝框标出的这条线程是 WAIT 状态,表明这条线程是空闲状态,但是从日志中我看到这条线程并没有完成它的任务,因为这个中心的数据有10万条,但是日志显示它只跑到了一半,之后就再无关于此中心的日志了。
  这是什么原因?调试及原因
  可以想到的是,这条线程因为某些原因被阻塞了,并且没有继续进行下去,但是日志又没有任何异常信息...
  可能有经验的工程师已经知道了原因...
  由于个人水平的线程,暂时没有找到原因的我只能放弃使用线程池,乖乖用单线程跑...
  幸运的是,单线程跑的任务竟然抛错了(为什么要说幸运?),于是马上想到,之前那条 WAIT 状态的线程可能是因为同样的抛错所以被中断了,导致任务没有继续进行下去。
  为什么说幸运?因为如果单线程的任务没有抛错的话,我可能很久都想不到是这个原因。深入探究线程池的异常处理
  工作上的问题到这里就找到原因了,之后的解决过程也十分简单,这里就不提了。
  但是疑问又来了,为什么使用线程池的时候,线程因异常被中断却没有抛出任何信息呢?还有平时如果是在 main 函数里面的异常也会被抛出来,而不是像线程池这样被吞掉。
  如果子线程抛出了异常,线程池会如何进行处理呢?
  我提交任务到线程池的方式是: threadPoolExecutor.submit(Runnbale task); ,后面了解到使用 execute() 方式提交任务会把异常日志给打出来,这里研究一下为什么使用 submit 提交任务,在任务中的异常会被"吞掉"。
  对于 submit() 形式提交的任务,我们直接看源码:public Future<?> submit(Runnable task) {     if (task == null) throw new NullPointerException();     // 被包装成 RunnableFuture 对象,然后准备添加到工作队列     RunnableFuture ftask = newTaskFor(task, null);     execute(ftask);     return ftask; }
  它会被线程池包装成 RunnableFuture 对象,而最终它其实是一个 FutureTask 对象,在被添加到线程池的工作队列,然后调用 start() 方法后, FutureTask 对象的 run() 方法开始运行,即本任务开始执行。public void run() {     if (state != NEW || !UNSAFE.compareAndSwapObject(this,runnerOffset,null, Thread.currentThread()))         return;     try {         Callable c = callable;         if (c != null && state == NEW) {             V result;             boolean ran;             try {                 result = c.call();                 ran = true;             } catch (Throwable ex) {                 // 捕获子任务中的异常                 result = null;                 ran = false;                 setException(ex);             }             if (ran)                 set(result);         }     } finally {         runner = null;         int s = state;         if (s >= INTERRUPTING)             handlePossibleCancellationInterrupt(s);     } }
  在 FutureTask 对象的 run() 方法中,该任务抛出的异常被捕获,然后在setException(ex); 方法中,抛出的异常会被放到 outcome 对象中,这个对象就是 submit() 方法会返回的 FutureTask 对象执行 get() 方法得到的结果。但是在线程池中,并没有获取执行子线程的结果,所以异常也就没有被抛出来,即被"吞掉"了。
  这就是线程池的 submit() 方法提交任务没有异常抛出的原因。线程池自定义异常处理方法
  在定义 ThreadFactory 的时候调用setUncaughtExceptionHandler方法,自定义异常处理方法。 例如:ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()                 .setNameFormat("judge-pool-%d")                 .setUncaughtExceptionHandler((thread, throwable)-> logger.error("ThreadPool {} got exception", thread,throwable))                 .build();
  这样,对于线程池中每条线程抛出的异常都会打下 error 日志,就不会看不到了。后续
  在修复了单个线程任务的异常之后,我继续使用线程池进行重新统计业务,终于跑完了,也终于完成了这个任务。
  小结:使用线程池时需要注意,子线程的异常,如果没有被捕获就会丢失,可能会导致后期根据日志调试时无法找到原因。
  作者:Planeswalker23
  链接:https://juejin.im/post/5ed07167f265da7714710d46

8月终于等到XsMax降到2999了进入到现在8月份,很多想要换iPhone的小伙伴都把目光转向iPhone11身上,毕竟现在新款机型中性价比比较高的,那么现在去入手一款iPhone11还值吗?。在我的体验看来,它并NvidiaRTXA2000登场旗下最小型显卡8nm制程Nvidia今天推出了为专业工作室而设计的RTXA2000。它是Nvidia迄今为止最小的显卡,可以轻松挤入小型计算机机箱。与Nvidia的Quadro系列一样,RTXA2000主苹果新技术大公开,颠覆端到端加密近日苹果发布了一项专门针对于扫描检测儿童色情虐待内容的技术,主要是通过对于iPhone等各类苹果设备上所接收到的图片信息进行哈希值的提取,之后再与国家失踪和被剥削儿童中心的数据库信华为最差的产品荣耀掉分平板说华为现在在国内手机排行第一没毛病把,它的大部分手机都很好用,无论是mate犀利还是nova系列,其功能针对的受众人群也是相得益彰。人无完人,品牌也不可能做到十全十美,比如华为最烂特斯拉竞争对手要建第二工厂马斯克暗讽其不会走就想跑特斯拉CEO埃隆马斯克向亚马逊与福特支持的电动汽车初创公司Rivian发出建议别没学会走就想跑,在匆忙建造第二家工厂之前,先搞定你们的第一家工厂。本周较早时有报道称,Rivian将成本控制新招苹果将镜头组装交给富士康芯研所消息,苹果可能为了缩减成本,将镜头部分的组装交给富士康来完成。据TheElec报道,韩国公司HyvisionSystem将为富士康提供镜头模块检测设备,很可能意味着富士康来负P50Pro屏幕第一惹争议DxO我们看的是屏幕体验昨天的时候,DxO公布了华为P50Pro屏幕方面的成绩,该手机在DxO的屏幕排行里以93分名列第一,超越了三星顶级旗舰S21和iPhone12ProMax,这一分数公布之后,引起了MiniLED!京东方将获得苹果高端订单苹果供应链又有新变化。天风国际证券分析师郭明錤近日发表最新报告指出,2021第三季新款MacBookPro的MiniLED面板供应商是LGDisplay与SharpGIS预测202一块屏幕2500,华为P50Pro公布售后价格,DXO认定的冠军贵不贵?华为P50Pro于8月12日上午1008正式开售,各大电商平台及线下门店陆续发货,参加预定的小伙伴不少已经拿到产品。与此同时,华为正式公布该机售后配件维修价格,单单屏幕费用就要25TrendForce苹果iPhone13系列定价与iPhone12系列相似IT之家8月13日消息苹果有望在下个月推出iPhone13系列新机,TrendForce集邦咨询近日对这些设备的参数做出了预测。TrendForce表示,其最新调查表明,iPhon苹果手机充电时显示不支持此配件,这是怎么回事啊?数据线不是原装产品的缘故,苹果手机对数据线(充电线)的要求非常严格,当出现不支持此配件时,必须更换原装或质量好的数据线,长期使用不合格线材会降低手机电池的寿命,不要为了贪方便而因小
宋PLUS新能源享受补贴送大礼包2022年4月28日2022年4月28日,比亚迪海洋盛世新景灿邦新店宋PLUS新能源享受补贴送大礼包,感兴趣的朋友可以到店咨询购买,具体优惠信息如下1。焕新礼首付15起2。臻选礼购iperf3网络性能测试工具及完整版教程1,iperf3简介iPerf3是用于主动测试IP网络上最大可用带宽的工具。它支持时序缓冲区协议(TCP,UDP,SCTP与IPv4和IPv6)有关的各种参数。对于每次测试,它都会闲置的手机不要浪费,放在公司实现手机远程打卡真的香由于手机市场的饱和状态以及竞争激烈程度,促使手机更新迭代的速度非常快,导致我国的闲置手机数量逐年增长。据统计我国2015年手机回收总量为5098万部,2020年手机回收总量为170收到奇怪短信?中国移动中国联通回应来了每经编辑王月龙,易启江据央视新闻报道,昨日晚间开始,有不少网友反映,收到奇怪的短信。短信内容是一连串1234567890的重复数字,收到奇怪短信有136137号段发送方则基本都是1我国电子商务领域知识产权大保护格局正形成来源光明网光明日报中国电子商务知识产权发展研究报告(2021)发布我国电子商务领域知识产权大保护格局正形成光明日报北京4月28日电(记者张亚雄)国家知识产权局知识产权发展研究中心2祥鑫科技新能源汽车业务占比将逐步提升中证网讯(记者董添)近日,祥鑫科技接受机构调研时指出,目前公司已为广汽埃安蔚来汽车比亚迪小鹏汽车等新能源汽车供应车身结构件为宁德时代国轩高科亿纬锂能塔菲尔孚能科技欣旺达远景动力巨湾央行设立2000亿再贷款,强化金融支持科技创新4月28日,人民银行官方发布消息称,为贯彻落实党中央国务院决策部署,强化国家战略科技力量,推进关键核心技术攻关和自主创新,根据国务院常务会议要求,人民银行设立科技创新再贷款。人民银2022年4月29日币圈晨间新闻一分钟速览关键词俄罗斯沃尔玛谷歌CEODior贝莱德香港RoninConvex1。俄罗斯预计将于5月推出规范加密货币的法案2。沃尔玛成立探索元宇宙和Web3的创新部门3。前谷歌CEO已购买少mybatis多条件批量删除整理批量增加insertidbatchSaveUserinsertintotuser(username,sex)values!动态SQL之foreach的用法!collectionus苹果宣布iPhone13Pro系列增产1000万部,同时下架这些应用根据韩媒最新报道称,由于iPhone13系列销量火爆,苹果将原先计划在第二季度生产的iPhone13Pro系列增加至1000万部。据业内人士透露,原先苹果计划在第二季度生产100万苹果终于推出iPhone自助维修服务,可以自行购买电池和屏幕维修iPhone自助维修上线苹果在近日正式上线了官方自助维修服务,部分地区的用户可以直接在官网购买维修配件,租借维修工具等,对自己的iPhone进行维修。和线下拿去维修一样,苹果提供的