Java中如何实现线程的超时中断

转载自  Java中如何实现线程的超时中断

背景

之前在实现熔断降级组件的时候,需要实现接口请求的超时中断。意思是,业务在使用熔断降级功能时,在平台上设置了一个超时时间,如果请求进入熔断器开始计时,接口在超时时间内没有响应,则需要提早中断该请求并返回。

比如正常下游接口的超时时间为800ms,但是因为自身业务的特殊需求,最多只能等200ms,如果指定之内没有数据返回,则返回降级数据。这里处理请求的线程可以看成是tomcat线程池中的一个线程,如果通过线程池返回的Future,可以很轻松的实现超时中断返回,但是当前情况下,并不能拿到Futrue,又不想额外引入一个线程池,所以需要另外一种实现思路。

思路

中断一个线程的思路有哪些? 除了已经废弃的Thread.stop, Thread.suspend, Thread.resume 方法,剩下的貌似只有一种方案了,就是调用当前线程的 interrupt(),但是这个方法的作用并不是中断线程,而是设置一个标识,通知该线程可以被中断了,到底是继续执行,还是中断返回,由线程本身自己决定。

具体来说,当对一个线程调用了 interrupt()之后,如果该线程处于被阻塞状态(比如执行了wait、sleep或join等方法),那么会立即退出阻塞状态,并抛出一个 InterruptedException异常,在代码中catch这个异常进行后续处理。如果线程一直处于运行状态,那么只会把该线程的中断标志设置为 true,仅此而已,所以 interrupt()并不能真正的中断线程,不过在rpc调用的场景中,请求线程一般都处于阻塞状态,等待数据返回,这时 interrupt()方法是可以派上用场的。

那么,要实现指定超时时间内中断请求线程,还有最后一个问题需要解决:什么时候,由谁去执行 interrupt()方法?

必然这个方法只能由其它线程来执行了(自己都阻塞了,执行个鬼),而且是在请求进入熔断器时,并在超时时间之后执行,有点绕,比如超时时间是200ms,那么请求进入熔断器之后,再过200ms,就执行 interrupt(),但是在200ms之内有数据返回,那么就不执行 interrupt()了。

实现

需求已经很明确了,相当于延迟执行一个task,其内部逻辑就是执行请求线程的 interrupt(),当然还有其它的逻辑。

Runnable task = new Runnable() {@Overridepublic void run() {try {thread.interrupt();// 取消定时器任务f.cancel();} catch (Exception e) {logger.error("Failed while ticking TimerListener", e);}}
};

Doug Lea大神提供的 ScheduledThreadPoolExecutor可以很好的满足这个需求,通过 scheduleAtFixedRate方法可以很方便的实现在延迟指定时间之后执行提交的任务。

 

ScheduledFuture<?> f = executor.scheduleAtFixedRate(task, timeout, timeout, TimeUnit.MILLISECONDS);

在请求进入熔断器时,顺便提交一个任务到线程池中等待执行,如果接口在超时时间内没有返回,那么该任务会被触发,并执行请求线程的 interrupt方法,这样就实现了请求线程的中断(因为这时请求线程正在被阻塞,等待数据返回),另外需要清空定时任务,不然这个任务会一直执行。

如果接口正常返回了,也要记得清空定时任务,并且在请求退出熔断器的时候,记得恢复请求线程的中断标识,如何恢复?在请求线程中执行下面代码即可。

Thread.interrupted();// 内部逻辑
public static boolean interrupted() {return currentThread().isInterrupted(true);
}// 参数为true,可以清除中断标识
private native boolean isInterrupted(boolean ClearInterrupted);

执行当前线程(即请求线程)的isInterrupted方法。

使用这种方式实现请求的超时中断,在QPS很高的情况下,会有额外的性能损失,因为每次请求都要提交一个任务到线程池中等待执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324359.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GDOI2018-《被虐记》

序章 五一劳动节当然是来劳动的啦&#xff01;于是乎五一就变成一件不存在的事&#xff0c;放学那天的中午就坐车去中山了。 然后睡了一会就快到了&#xff0c;下了高速&#xff0c;突然想起来这次带来手机就照了一张照。然后就到酒店了。附近也有挺多吃的&#xff0c;酒店一…

DDD理论学习系列(10)-- 聚合

1.引言 聚合&#xff0c;最初是UML类图中的概念&#xff0c;表示一种强的关联关系&#xff0c;是一种整体与部分的关系&#xff0c;且部分能够离开整体而独立存在&#xff0c;如车和轮胎。 在DDD中&#xff0c;聚合也可以用来表示整体与部分的关系&#xff0c;但不再强调部分…

#面试!,一定要注意,避免踩这些雷!!

大家好&#xff0c;我是雄雄。前言今天&#xff0c;对2班的同学们进行了模拟面试&#xff0c;由于学生们第一次参与模拟面试&#xff0c;所以会出现各种各样的问题&#xff0c;有应该出的&#xff0c;也有不该出的&#xff0c;现在做个简单的总结&#xff0c;供三班的孩子们参考…

一次动态代理的填坑之旅

转载自 一次动态代理的填坑之旅 背景 想在现有的接口加上熔断降级或者限流的功能&#xff0c;比较好的方式是通过注解的方式&#xff0c;并基于动态代理进行实现&#xff0c;下面代码是Rhino的实现 Rhino public class ServiceImpl {Degrade(rhinoKey "syncMethod-0&…

3班的第一次模拟面试

大家好&#xff0c;我是雄雄&#xff0c;前几天总结了下面试别的班时所出现的问题&#xff0c;今天&#xff0c;3班进行了第一次模拟面试。虽然在面试之前千叮咛万嘱咐&#xff0c;但是在正式模拟面试时还是有些问题。一方面由于这样的模拟面试以前没有过&#xff0c;所以紧张过…

漫画:如何实现大整数相加

转载自 漫画&#xff1a;如何实现大整数相加 在程序中列出的 “竖式” 究竟是什么样子呢&#xff1f;我们以 426709752318 95481253129 为例&#xff0c;来看看大整数相加的详细步骤&#xff1a; 第一步&#xff0c;把整数倒序存储&#xff0c;整数的个位存于数组0下标位置&…

ssl2644-线段树练习1【线段树】

正题 题意 一块长m的墙&#xff0c;有n个大小不同的盒子放在前面&#xff0c;求没有被挡住的墙的总长度 解题思路 用线段树&#xff0c;0表示有没被遮挡的&#xff0c;1表示完全被遮挡&#xff0c;-1表示有遮挡的和没遮挡的。然后记数。 代码 #include<cstdio> usin…

Entity Framework Core 执行SQL语句和存储过程

无论ORM有多么强大&#xff0c;总会出现一些特殊的情况&#xff0c;它无法满足我们的要求。在这篇文章中&#xff0c;我们介绍几种执行SQL的方法。 表结构 在具体内容开始之前&#xff0c;我们先简单说明一下要使用的表结构。 public class Category{ public …

我去,终于解决了!

大家好&#xff0c;我是雄雄。今天给大家带来的是【IntelliJ IDEA中配置SSM框架总是报错&#xff0c;启动不了Tomcat的解决方法】。前言以前不管是在开发还是在授课&#xff0c;使用的软件要么是eclipse&#xff0c;要么就是myeclipse&#xff0c;最近听闻身边的人都在用idea,并…

EF Core 插件 —— ToSql

背景 在使用Entity Framework Core进行开发时&#xff0c;若不使用Logger很难查看到一个查询的SQL语句&#xff0c;同时也有些开发者因为不了解EF Core哪些Linq可以Translate成SQL&#xff0c;哪些不能而踩坑导致全表查询的&#xff0c;因此开发了Pomelo.EntityFrameworkCore.…

如何在idea中使用jstl标签库

大家好&#xff0c;我是雄雄&#xff0c;上期我们解决了个bug&#xff0c;详情点击这里&#xff1a;我去&#xff0c;终于解决了 &#xff0c;今天&#xff0c;我们来看看【如何在idea中使用jstl标签库】前言&#xff1a;像myeclipse和eclipse这种编辑器&#xff0c;jstl标签库…

ssl2645-线段树练习2【线段树】

正题 题意 一块长m的墙&#xff0c;有n个大小不同的盒子放在前面&#xff0c;求可以看到多少盒子 解题思路 用线段树&#xff0c;用cover表示可以看到的颜色&#xff0c;-1表示可以看到多种颜色&#xff0c;然后统计&#xff0c;用find数组去重。 代码 #include<cstdio…

Redis单线程架构

转载自 Redis单线程架构 redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务。 引出单线程模型 开启三个redis-cli客户端同时执行命令&#xff1a; 1、客户端1设置一个字符串键值对&#xff1a; 2、客户端2对counter自增操作&#xff1a; 3、客户端3对c…

idea中报错……的解决方式!

大家好&#xff0c;我是雄雄&#xff0c;在用idea的时候&#xff0c;又报错了&#xff0c;哈哈哈。前言还以为所有的问题都解决的差不多了&#xff0c;于是就找了个jsp的案例用idea来熟练熟练&#xff0c;刚开始的时候顺风顺水&#xff0c;按照之前的方法搭建项目&#xff0c;没…

.NET Core快速入门教程 5、使用VS Code进行C#代码调试的技巧

.NET Core 快速入门教程 .NET Core 快速学习、入门系列教程。这个入门系列教程主要跟大家聊聊.NET Core的前世今生&#xff0c;以及Windows、Linux&#xff08;CentOS、Ubuntu&#xff09;基础开发环境的搭建、第一个.NET Core App&#xff0c;以及开发工具的使用、调试技巧&a…

ssl2646-线段树练习3【线段树】

正题 题意 一条长m线&#xff0c;有n条长度不同的线段&#xff0c;求该线被分割成多少段 解题思路 标记颜色&#xff0c;然后统计是用一个color表示上次搜到的(因为线段树的查找顺序是从左到右的)去重 代码 #include<cstdio> #include<cstring> using namespa…