当前位置: 首页 > news >正文

JAVA线程执行中断方式和ElasticSearch未捕获异常的处理方式

JAVA线程执行中断方式

Java中只能通过协作的方式取消

  • 第一种是通过标志位实现,假设有个计算所有素数的任务,每次计算前检查下是否取消的标志位,如果为true则退出计算。调用方想要取消任务的话,则将标志位设为true。但这种方法无法再计算的过程中取消任务,像是一些阻塞调用无法被取消

  • 第二种是中断,用于通过协作机制停止线程继续执行任务,原理是向进程发送中断请求将标记线程为Interrupted,线程会在下一个合适的时刻停止运行,阻塞的库方法例如Thread.sleep Object.wait 都会响应中断,抛出InterruptedException意味着阻塞操作因为中断结束,但不能保证响应速度。

    通常任务不会在自己拥有的线程执行,而是在某个服务的线程池中执行,因此任务应该保存阻塞状态,使得线程能处理中断。这就是库函数抛出InterruptedException的原因。同时任务也不能对线程处理中断的策略做任何假设。

    有两种处理中断的方法,千万不要catch掉异常什么也不做,除非你拥有该线程

    • 向外抛出InterruptedException
    • 调用 Thread.currentThread().interrupt();恢复中断状态

    例如在向线程池提交runnable执行时,runnable调用了阻塞库函数则需要写处理中断的逻辑,逻辑中要使用上面处理中断的两种方法之一,因为线程池会处理线程遇到阻塞,将线程从可用线程列表删除,统计审计信息等操作

    final void runWorker(Worker w) {Thread wt = Thread.currentThread();Runnable task = w.firstTask;w.firstTask = null;w.unlock(); // allow interruptsboolean completedAbruptly = true;try {while (task != null || (task = getTask()) != null) {w.lock();try {beforeExecute(wt, task);Throwable thrown = null;try {task.run(); // 执行runnable} catch (RuntimeException x) {thrown = x; throw x;} catch (Error x) {thrown = x; throw x;} catch (Throwable x) {thrown = x; throw new Error(x);} finally {afterExecute(task, thrown);}} finally {task = null;w.completedTasks++;w.unlock();}}completedAbruptly = false;} finally {processWorkerExit(w, completedAbruptly); // 处理InteruptException}}
    private void processWorkerExit(Worker w, boolean completedAbruptly) {if (completedAbruptly) // If abrupt, then workerCount wasn't adjusteddecrementWorkerCount();final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {completedTaskCount += w.completedTasks;workers.remove(w);} finally {mainLock.unlock();}tryTerminate();int c = ctl.get();if (runStateLessThan(c, STOP)) {if (!completedAbruptly) {int min = allowCoreThreadTimeOut ? 0 : corePoolSize;if (min == 0 && ! workQueue.isEmpty())min = 1;if (workerCountOf(c) >= min)return; // replacement not needed}addWorker(null, false);}}
    

还有一种方法是使用future来中断任务执行,使用submit.cancel(true),内部也是利用了Thread.interrupt

ExecutorService executor = Executors.newFixedThreadPool(1);final Future<?> submit = executor.submit(() -> {});try {final Object o = submit.get(10, TimeUnit.MILLISECONDS);} catch (TimeoutException e) {}finally {submit.cancel(true); // 正常得到结果后再cancel也无影响}

未捕获异常的处理方式

线程因为异常或者error退出后,会向System.error输出堆栈,但线上程序一般通过日志来排查问题而不是控制台输出。Java支持配置Thread.UncaughtExceptionHandler处理这种未被捕获的Throwable,程序最好自己实现该接口,至少将异常堆栈输出到日志中,下面是ES实现的Thread.UncaughtExceptionHandler(去掉了一些细节),ES将异常信息输出到了日志文件。

class ElasticsearchUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {private static final Logger logger = LogManager.getLogger(ElasticsearchUncaughtExceptionHandler.class);@Overridepublic void uncaughtException(Thread thread, Throwable t) {if (isFatalUncaught(t)) {onFatalUncaught(thread.getName(), t);} else {onNonFatalUncaught(thread.getName(), t);}}static boolean isFatalUncaught(Throwable e) {return e instanceof Error;}void onFatalUncaught(final String threadName, final Throwable t) {final String message = "fatal error in thread [" + threadName + "], exiting";logger.error(message, t);Terminal.DEFAULT.errorPrintln(message);t.printStackTrace(Terminal.DEFAULT.getErrorWriter());// Without a final flush, the stacktrace may not be shown before ES exitsTerminal.DEFAULT.flush();}void onNonFatalUncaught(final String threadName, final Throwable t) {final String message = "uncaught exception in thread [" + threadName + "]";logger.error(message, t);Terminal.DEFAULT.errorPrintln(message);t.printStackTrace(Terminal.DEFAULT.getErrorWriter());// Without a final flush, the stacktrace may not be shown if ES goes on to exitTerminal.DEFAULT.flush();}}

相关文章:

  • Meta开源Code Llama 70B,缩小与GPT-4之间的技术鸿沟
  • leetcode-存在重复元素 II
  • 批量将csv文件转成excel
  • 2023年春秋杯网络安全联赛冬季赛_做题记录
  • Linux/ScriptKiddie
  • 18.通过telepresence调试部署在Kubernetes上的微服务
  • C++对象模型和this指针,const修饰成员函数详解
  • 【爬虫用户代理和ip自动生成】
  • 大中型企业DevSecOps建设
  • kubernetes-快速部署一套k8s集群
  • GDB调试技巧实战--自动化画出类关系图
  • 【ES6】一个页面上需要等两个或多个ajax的数据请求成功以后才正常显示(使用Promise.all和Promise.race)
  • HTTPS 之fiddler抓包--jmeter请求
  • 人脸识别 FaceNet人脸识别(一种人脸识别与聚类的统一嵌入表示)
  • 【51单片机】点亮第一个LED灯
  • 【刷算法】求1+2+3+...+n
  • Angular 响应式表单之下拉框
  • avalon2.2的VM生成过程
  • IP路由与转发
  • Js基础知识(四) - js运行原理与机制
  • MySQL QA
  • ng6--错误信息小结(持续更新)
  • Redis 懒删除(lazy free)简史
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • 半理解系列--Promise的进化史
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 你对linux中grep命令知道多少?
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (52)只出现一次的数字III
  • (Python第六天)文件处理
  • (差分)胡桃爱原石
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (四)模仿学习-完成后台管理页面查询
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转)四层和七层负载均衡的区别
  • (转载)虚函数剖析
  • ***检测工具之RKHunter AIDE
  • *p++,*(p++),*++p,(*p)++区别?
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .NET 使用 XPath 来读写 XML 文件
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .net开发时的诡异问题,button的onclick事件无效
  • /etc/sudoers (root权限管理)
  • []利用定点式具实现:文件读取,完成不同进制之间的
  • [20160807][系统设计的三次迭代]
  • [2017][note]基于空间交叉相位调制的两个连续波在few layer铋Bi中的全光switch——
  • [240607] Jina AI 发布多模态嵌入模型 | PHP 曝新漏洞 | TypeScript 5.5 RC 发布公告