`

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.lang.Thread`类也提供了一种实现线程超时的方法,通过使用`join`方法。`join`可以等待某个线程结束,同时可以设置一个等待时限。 ```java Thread thread = new Thread(() -&gt; { // 需要监控的线程代码 ...

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

    在Java编程中,控制程序执行超时是一项关键任务,特别是在多线程环境下,我们需要确保某个任务不会无限期地运行,导致资源浪费或者阻塞其他重要任务。本篇将深入探讨如何利用Java的线程和定时器(Timer)来实现这个...

    Java线程超时控制的实现.docx

    本文将详细介绍两种实现Java线程超时控制的方法,并对其原理和应用场景进行深入分析。 #### 二、方法1:使用守护线程实现超时控制 这种方法通过创建一个守护线程来监控目标线程的执行时间。当达到预设的时间阈值时...

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

    Java中实现线程的超时中断方法实例 概述:在 Java 中实现线程的超时中断是非常重要的,特别是在熔断降级组件中。熔断降级组件需要在指定的超时时间内中断请求线程,以避免请求长时间阻塞系统资源。在这篇文章中,...

    java超时控制

    4. **多线程超时** 在多线程环境下,可以使用`Thread.join(long timeout)`方法,让当前线程等待指定时间,如果目标线程还未结束,就返回,避免死锁。 5. **数据库连接超时** 数据库连接池如C3P0或HikariCP允许...

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

    `newFixedThreadPool`是`java.util.concurrent`包中的一个线程池工厂方法,用于创建固定数量线程的线程池。`FutureTask`则是表示异步计算的结果,它实现了`RunnableFuture`接口,提供了对任务状态的查询和结果获取。...

    Java线程状态流转图

    Java线程状态流转图中,以下方法与线程状态转换相关: * Object.wait():使线程从RUNNABLE状态转换到WAITING状态。 * Object.notify():使线程从WAITING状态转换到RUNNABLE状态。 * Object.notifyAll():使多个线程...

    JAVA线程学习(源代码)

    本资源"JAVA线程学习(源代码)"提供了关于Java线程的源代码示例,帮助我们深入理解和实践线程的使用。 首先,我们要理解Java中的线程模型。Java线程由`java.lang.Thread`类或`java.util.concurrent.Executor`框架来...

    Java Socket/ServerSocket 多线程下聊天室系统

    Java提供了多种同步机制,如`synchronized`关键字、`wait()`、`notify()`和`notifyAll()`方法,以及`ReentrantLock`等高级锁。合理使用这些机制可以确保消息的正确顺序和数据完整性。 5. **设计模式**: 考虑到...

    Java线程使用教程

    Java线程是Java编程语言中的一个核心概念,它允许程序同时执行多个任务,极大地提高了程序的并发性和效率。本教程将深入探讨Java线程的使用,帮助开发者掌握这一关键技术。 一、线程基础 1. **线程的概念**:线程...

    Java线程培训资料

    1. **线程控制方法** - `Thread.sleep(long millis)`: 让当前正在执行的线程暂停执行指定时间,让出CPU给其他线程使用。 - `Thread.yield()`: 提示当前线程让出CPU时间片,但不一定立即生效。 - `Thread.suspend...

    java多线程经典案例

    Java提供了三种线程状态:新建(New)、运行(Runnable)、阻塞(Blocked)、等待(Waiting)、超时等待(Timed Waiting)和终止(Terminated)。阻塞状态通常发生在线程等待I/O操作完成、调用sleep()方法、等待锁...

    java多线程编程总结

    Java线程的状态包括新建 (`NEW`)、就绪 (`RUNNABLE`)、阻塞 (`BLOCKED`)、等待 (`WAITING`)、超时等待 (`TIMED_WAITING`) 和终止 (`TERMINATED`)。 #### 五、Java线程:线程的同步与锁 - **线程同步** 线程同步...

    线程超时死掉

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

    java 多线程并发实例

    在Java编程中,多线程并发是...总之,Java的多线程并发实例可以帮助我们更好地理解和实践线程控制、同步机制以及经典的设计模式,提升我们的编程能力。通过不断学习和实践,我们可以编写出高效、安全的多线程并发程序。

    java 线程池源代码

    3. `keepAliveTime`: 当线程数超过核心线程数时,空闲线程等待新任务的最长时间,超时会被终止。 4. `unit`: keepAliveTime的时间单位。 5. `workQueue`: 任务队列,用于存储待执行的任务。常见的有`...

    Java多线程管理示例

    Java通过Thread类提供了对线程的封装和控制,我们可以通过创建Thread对象并重写其run()方法来实现并发执行的任务。 接着,我们来看看线程同步。在多线程环境下,共享资源的访问可能导致数据不一致,为解决这个问题...

    java线程与并行(主要讲解java的nio包某些内容)

    ### Java线程与并行详解 #### 一、Java线程基础 在Java中,**线程**是一种轻量级的进程,它允许一个程序同时执行多个任务,从而提高程序的执行效率。Java从1.0版本开始就支持多线程编程,并在后续版本中不断完善。...

    Java多线程编程核心技术_完整版_java_

    Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程主要通过继承Thread类或实现Runnable接口来实现。本教程《Java多线程编程核心技术》将...

Global site tag (gtag.js) - Google Analytics