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.lang.Thread`类也提供了一种实现线程超时的方法,通过使用`join`方法。`join`可以等待某个线程结束,同时可以设置一个等待时限。 ```java Thread thread = new Thread(() -> { // 需要监控的线程代码 ...
在Java编程中,控制程序执行超时是一项关键任务,特别是在多线程环境下,我们需要确保某个任务不会无限期地运行,导致资源浪费或者阻塞其他重要任务。本篇将深入探讨如何利用Java的线程和定时器(Timer)来实现这个...
本文将详细介绍两种实现Java线程超时控制的方法,并对其原理和应用场景进行深入分析。 #### 二、方法1:使用守护线程实现超时控制 这种方法通过创建一个守护线程来监控目标线程的执行时间。当达到预设的时间阈值时...
Java中实现线程的超时中断方法实例 概述:在 Java 中实现线程的超时中断是非常重要的,特别是在熔断降级组件中。熔断降级组件需要在指定的超时时间内中断请求线程,以避免请求长时间阻塞系统资源。在这篇文章中,...
4. **多线程超时** 在多线程环境下,可以使用`Thread.join(long timeout)`方法,让当前线程等待指定时间,如果目标线程还未结束,就返回,避免死锁。 5. **数据库连接超时** 数据库连接池如C3P0或HikariCP允许...
`newFixedThreadPool`是`java.util.concurrent`包中的一个线程池工厂方法,用于创建固定数量线程的线程池。`FutureTask`则是表示异步计算的结果,它实现了`RunnableFuture`接口,提供了对任务状态的查询和结果获取。...
Java线程状态流转图中,以下方法与线程状态转换相关: * Object.wait():使线程从RUNNABLE状态转换到WAITING状态。 * Object.notify():使线程从WAITING状态转换到RUNNABLE状态。 * Object.notifyAll():使多个线程...
本资源"JAVA线程学习(源代码)"提供了关于Java线程的源代码示例,帮助我们深入理解和实践线程的使用。 首先,我们要理解Java中的线程模型。Java线程由`java.lang.Thread`类或`java.util.concurrent.Executor`框架来...
Java提供了多种同步机制,如`synchronized`关键字、`wait()`、`notify()`和`notifyAll()`方法,以及`ReentrantLock`等高级锁。合理使用这些机制可以确保消息的正确顺序和数据完整性。 5. **设计模式**: 考虑到...
Java线程是Java编程语言中的一个核心概念,它允许程序同时执行多个任务,极大地提高了程序的并发性和效率。本教程将深入探讨Java线程的使用,帮助开发者掌握这一关键技术。 一、线程基础 1. **线程的概念**:线程...
1. **线程控制方法** - `Thread.sleep(long millis)`: 让当前正在执行的线程暂停执行指定时间,让出CPU给其他线程使用。 - `Thread.yield()`: 提示当前线程让出CPU时间片,但不一定立即生效。 - `Thread.suspend...
Java提供了三种线程状态:新建(New)、运行(Runnable)、阻塞(Blocked)、等待(Waiting)、超时等待(Timed Waiting)和终止(Terminated)。阻塞状态通常发生在线程等待I/O操作完成、调用sleep()方法、等待锁...
Java线程的状态包括新建 (`NEW`)、就绪 (`RUNNABLE`)、阻塞 (`BLOCKED`)、等待 (`WAITING`)、超时等待 (`TIMED_WAITING`) 和终止 (`TERMINATED`)。 #### 五、Java线程:线程的同步与锁 - **线程同步** 线程同步...
Future接口是Java线程Future模式的实 现,可以来进行异步计算。 Future模式可以这样来描述:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时 间之后,我就便...
在Java编程中,多线程并发是...总之,Java的多线程并发实例可以帮助我们更好地理解和实践线程控制、同步机制以及经典的设计模式,提升我们的编程能力。通过不断学习和实践,我们可以编写出高效、安全的多线程并发程序。
3. `keepAliveTime`: 当线程数超过核心线程数时,空闲线程等待新任务的最长时间,超时会被终止。 4. `unit`: keepAliveTime的时间单位。 5. `workQueue`: 任务队列,用于存储待执行的任务。常见的有`...
Java通过Thread类提供了对线程的封装和控制,我们可以通过创建Thread对象并重写其run()方法来实现并发执行的任务。 接着,我们来看看线程同步。在多线程环境下,共享资源的访问可能导致数据不一致,为解决这个问题...
### Java线程与并行详解 #### 一、Java线程基础 在Java中,**线程**是一种轻量级的进程,它允许一个程序同时执行多个任务,从而提高程序的执行效率。Java从1.0版本开始就支持多线程编程,并在后续版本中不断完善。...
Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程主要通过继承Thread类或实现Runnable接口来实现。本教程《Java多线程编程核心技术》将...