`

java 线程/方法超时控制

    博客分类:
  • java
 
阅读更多

 java 开发中经常遇到需要对线程、线程池、接口调用进行超时控制的需求,这种需求的场景往往是存在响应时间较长的接口或者方法,进行超时控制,避免因调用时间过长,影响调用者本身的性能甚至可用性,下面简单讨论下这些场合里超时控制的方法和工具。

1. Future 接口

    Future接口是Java标准API的一部分,在java.util.concurrent包中,配合有返回值的线程使用。使用较多的方法有future.get(),future.get(long timeout, TimeUnit unit),注意get方法是一个同步方法,Futrue对象可以监视目标线程调用call的情况,当你调用Future的get()方法以获得结果时,当前线程就开始阻塞,直接call方法结束返回结果,一般推荐使用future.get(long timeout, TimeUnit unit)。

ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Result> work = new Callable<Result>() {
    @Override
    public Result call() {
        // do something
        return  result
    }
};
Future<Result> future = executor.submit(work);
try {
    result = future.get(TIMEOUT, TIMEUNIT); 
} catch (TimeoutException e) { 
    ...
} catch (...) {
    ...
}

2. Guava SimpleTimeLimiter

    SimpleTimeLimiter 实现了TimeLimiter,本质是对Future的封装,通过设置超时时间,当调用超时,抛出超时异常,SimpleTimeLimiter中有两个方法,newProxy和callWithTimeout,其中newProxy通过JDK动态代理配合callWithTimeout实现超时拦截 ,callWithTimeout  通过Callable回调,实现超时拦截,newProxy可以对这个类里面每一个被调用的方法,实行超时拦截; callWithTimeout适用于仅对某一个方法,实行超时拦截。 

   示例:

SimpleTimeLimiter timeLimiter = new SimpleTimeLimiter();
Callable<Result<Object>> work = new Callable<Result<Object>>() {
    @Override
    public Result<Object> call() {
        // do something
        return  result
    }
};
try {
    result = limiter.callWithTimeout(work, TIMEOUT, TIMEUNIT, false);
} catch (UncheckedTimeoutException e) {
    ...
} catch (...) {
    ...
}     
public <T> T callWithTimeout(Callable<T> callable, long timeoutDuration, TimeUnit timeoutUnit, boolean amInterruptible) throws Exception {
        Preconditions.checkNotNull(callable);
        Preconditions.checkNotNull(timeoutUnit);
        Preconditions.checkArgument(timeoutDuration > 0L, "timeout must be positive: %s", new Object[]{Long.valueOf(timeoutDuration)});
        Future future = this.executor.submit(callable);
        try {
            if(amInterruptible) { // 可以被中断
                try {
                    return future.get(timeoutDuration, timeoutUnit);
                } catch (InterruptedException var8) { // 抛出中断异常
                    future.cancel(true);
                    throw var8;
                }
            } else { // 等到结果或者超时,再抛出中断
                return Uninterruptibles.getUninterruptibly(future, timeoutDuration, timeoutUnit);
            }
        } catch (ExecutionException var9) {
            throw throwCause(var9, true);
        } catch (TimeoutException var10) {
            future.cancel(true);
            throw new UncheckedTimeoutException(var10);
        }
    }

    其中 TIMEUNIT 是超时时间单位,值有纳秒、分秒、毫秒、秒、分钟、时、天, TIMEOUT是设置的超时时间。, 来看下callWithTimeout方法的第四个参数amInterruptible,这个参数为true,表示该work线程发生中断异常即刻向上抛出,false表示即使发生了中断异常,也要等到取到结果或者超时了,再重新设置中断标示位,向上抛出,共上层处理,具体使用中看选择。

    简单介绍完SimpleTimeLimiter的用法,下面来看一个开发过程中遇到的坑,我们先看下SimpleTimeLimiter类的构造方法:

public SimpleTimeLimiter(ExecutorService executor) {
    this.executor = (ExecutorService)Preconditions.checkNotNull(executor);
}
public SimpleTimeLimiter() {
    this(Executors.newCachedThreadPool());
}

    注意看,SimpleTimeLimiter的两个构造函数,有参构造函数的入参是一个线程池,无参构造函数则是在内部创建了一个newCachedThreadPool,上面示例创建SimpleTimeLimiter实例时没有带参数,如果这个SimpleTimeLimiter会被多次创建,则会有多个newCachedThreadPool,同时因为定义为private的,现象为一个线程池里只有一个线程,那程序将创建大量的线程,在持续高频率调用场景下,服务器的线程将会跑满,但是cpu是正常,因为这些线程基本是空跑,所以使用时。建议传入一个可控的(比如全局的)有限线程池,同时注意传入的executor不能为null,否则会抛空指针异常。

3. CountDownLatch

    CountDownLatch是一个同步工具类,在java.util.concurrent并发包中,协调线程之间的同步工作。一个线程可以通过CountDownLatch等待另外一些线程完成之后,再继续执行。CountDownLatch内部使用一个计数器实现这一功能。计数器初始值为被等待线程的数量。每一个线程完成自己任务后,计数器值减1。当计数器的值为0时,表示所有的线程都已经完成,这时在等待的阻塞线程就可以继续工作。

    看一下CountDownLatch的主要方法:

    a. public CountDownLatch(int count),构造方法,入参是计数器初始值,一般也即线程数,注意,这个值只在创建实例时被设置一次,后续不能改动。

    b. public await(),  public await(long timeout, TimeUnit unit), 其中await()没有超时时间,一直等待计数器减到0;有时候,某些线程的操作耗时非常长或者线程内部发生异常,为了不影响主线程的继续执行,建议使用await(timeout,unit)方法,其中timeout为超时时间,如果该时间小于等于零,则不会等待(设<=0没意义),unit为时间单位,当前线程是等待到超时时间结束,就不再阻塞,继续往下执行。await会抛出异常(InterruptedException),所以一般需要try catch住,但是注意设置的超时时间结束后,计数器没有为0时,当前序结束休眠,正常继续执行。同时子线程继续执行。

    c.  public countDown()方法,计数器减1,每调用一次,构造函数中初始化的count值减1,在配合await()使用这个方法时,未避免线程异常情况未执行减一操作,注意 countDown操作要放到finally{}中执行。

分享到:
评论

相关推荐

    java通过线程控制程序执行超时(新)

    java通过线程控制程序执行超时(新) 基本数据类型 反射 线程 超时

    Java线程超时监控

    讲解有关Java中多线程运行时针对单个线程的执行超时监控机制,用于处理单个线程执行控制

    java通过线程控制程序执行超时

    java通过线程控制程序执行超时,多线程,反射

    Java中实现线程的超时中断方法实例

    之前在使用Java实现熔断降级组件的时候,需要实现接口请求的超时中断,通过查找相关资料了解了相关的方法,下面这篇文章主要给大家介绍了关于Java中实现线程的超时中断的相关资料,需要的朋友可以参考下

    线程超时死掉

    Future接口是Java线程Future模式的实 现,可以来进行异步计算。 Future模式可以这样来描述:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时 间之后,我就便...

    BlockingQueue队列自定义超时时间取消线程池任务

    定义全局线程池,将用户的请求放入自定义队列中,排队等候线程调用,等待超时则自动取消该任务,实现超时可取消的异步任务

    Java同步线程模型分析与改进

    目前普遍采用急救包(Band-Aid)类库的方式解决Java 线程模型存在的同步问题,但类库中的代码很难或无法实 ...通过扩展语法方法解决了同步问题,以确保使用Java线程所开发的 程序的稳定、可靠和可优化。

    java多线程URL方式下载单个大文件

    Java代码,根据URL方式下载单个文件或者图片,根据文件大小进行分批启动多线程下载!

    浅谈java中异步多线程超时导致的服务异常

    下面小编就为大家带来一篇浅谈java中异步多线程超时导致的服务异常。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    Java CP/IP Socket编程

    4.1.1 Java 多线程..........78 4.1.2 服务器协议..........80 4.1.3 一客户一线程..........84 4.1.4 线程池..........86 4.1.5 系统管理调度:Executor接口..........89 4.2 阻塞和超时..........91 4.2.1 ...

    Java中停止线程执行的方法

    尽管可以在等待wait()条件那里放一个超时设置,但等待wait()的设计目的不是这样的,等待wait()在设计上是用于Java线程间的通信。 而使用睡眠sleep()方式,可以让线程从当前开始睡眠指定的时间。注意不要使用睡眠...

    个人总结的深入java多线程开发

    看完《think in java》多线程章节,自己写的多线程文档,还结合了其他的相关网络资料。 线程 一. 线程池 1)为什么要使用线程池 2 2)一个具有线程池的工作队列 3 3)使用线程池的风险: 4 4)有效使用线程池的原则 5...

    安卓,Android线程网络超时自动终止

    Android开发中经常需要调用线程访问网络,而手机的网络信号经常断断续续,容易出现网络超时的情况,这种情况下后台线程往往得不到关闭,浪费系统资源。 在下面的例子中使用了java 中的Timer类,对线程进行了约束,...

    浅谈Java线程间通信之wait/notify

    下面小编就为大家带来一篇浅谈Java线程间通信之wait/notify。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    Java HttpURLConnection超时和IO异常处理

    主要介绍了Java HttpURLConnection超时和IO异常处理的相关资料,需要的朋友可以参考下

    JAVA上百实例源码以及开源项目

     Java访问权限控制,为Java操作文件、写入文件分配合适的权限,定义写到文件的信息、定义文件,输出到c:/hello.txt、写信息到文件、关闭输出流。 Java绘制图片火焰效果 1个目标文件 摘要:Java源码,图形操作,火焰...

    JAVA上百实例源码以及开源项目源代码

     Java访问权限控制,为Java操作文件、写入文件分配合适的权限,定义写到文件的信息、定义文件,输出到c:/hello.txt、写信息到文件、关闭输出流。 Java绘制图片火焰效果 1个目标文件 摘要:Java源码,图形操作,火焰...

    java开源包4

    MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的Java包,主要特点是多线程、调度、JMX管理和批量执行报表,执行历史等。 SIP协议包 jSIP.tar jSIP这个Java包目标是用Java实现SIP(SIP:...

Global site tag (gtag.js) - Google Analytics