java并发编程之Future.get() 一直阻塞

本文讨论了在HTTP页面调用中,如何通过定义自定义RejectedExecutionHandler来处理过多请求导致的结果丢失问题,包括使用FutureTask取消执行和定制DiscardPolicy以确保适当的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自:https://blog.csdn.net/doctor_who2004/article/details/115647638

下面是个人理解结论:

场景:页面http调用,一次调用,底层同时调用多个服务,部分结果可丢失情形。

实现:

担心调用量太多,允许丢弃部分结果,并行执行,定义线程池。自定义RejectedExecutionHandler,取消执行( ((FutureTask) r).cancel(true)),这样应该是最合适的。以防万一,future外面还可以再加个超时时间。



executor.setQueueCapacity(0);
executor.setRejectedExecutionHandler(new MyDiscardPolicy ());

web调用时Executor.submit(),如果设置AbortPolicy时没有返回结果,只会抛出异常。这种情况可以自定义DiscardPolicy。

public static class MyDiscardPolicy implements RejectedExecutionHandler {
    /**
     * Creates a {@code DiscardPolicy}.
     */
    public Erp20DiscardPolicy() { }

    /**
     * Does nothing, which has the effect of discarding task r.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        loggerUtil.info(LogData.builder().data(" Erp20AbortPolicy Task " + r.toString() +" rejected from " + e.toString()));
        ((FutureTask) r).cancel(true);//这种会抛异常,future.get()时需要try catch
    }
}
for (Future<Map> future : futureList) {
    try {
        Map tempMap = future.get();        
    }catch (Exception e){
       // logger.error();
    }
}
<think>我们讨论的是Java中的Future.get()方法。FutureJava并发包(java.util.concurrent)中的一个接口,用于表示异步计算的结果。Future.get()方法用于获取计算结果,如果计算尚未完成,该方法会阻塞直到计算完成,或者可以设置超时时间。 ### 关键点: 1. **阻塞行为**:调用get()方法时,如果任务还没有完成,当前线程会被阻塞,直到任务完成。 2. **异常处理**:如果任务执行过程中抛出了异常,get()方法会抛出ExecutionException,我们可以通过这个异常获取到任务中抛出的原始异常。 3. **取消任务**:如果任务被取消,get()方法会抛出CancellationException。 4. **超时控制**:get()方法有两个重载版本: - `get()`: 无限期等待。 - `get(long timeout, TimeUnit unit)`: 等待指定的时间,如果超时任务还没完成,则抛出TimeoutException。 ### 代码示例 下面是一个使用Future和Callable的简单示例。我们创建一个线程池,提交一个Callable任务,然后通过Future.get()获取结果。 ```java import java.util.concurrent.*; public class FutureExample { public static void main(String[] args) { // 创建线程池 ExecutorService executor = Executors.newSingleThreadExecutor(); // 提交Callable任务 Future<String> future = executor.submit(() -> { // 模拟耗时操作 Thread.sleep(2000); return "Hello, Future!"; }); try { // 获取结果,最多等待3秒 String result = future.get(3, TimeUnit.SECONDS); System.out.println("Result: " + result); } catch (TimeoutException e) { System.err.println("Task timed out"); } catch (ExecutionException e) { System.err.println("Task execution failed: " + e.getCause()); } catch (InterruptedException e) { System.err.println("Task was interrupted"); } finally { // 关闭线程池 executor.shutdown(); } } } ``` ### 代码解释: 1. **创建线程池**:使用`Executors.newSingleThreadExecutor()`创建一个单线程的线程池。 2. **提交任务**:通过`executor.submit()`提交一个Callable任务(这里使用Lambda表达式)。该任务休眠2秒后返回一个字符串。 3. **获取结果**:调用`future.get(3, TimeUnit.SECONDS)`,设置超时时间为3秒。因为任务执行需要2秒,所以不会超时,正常返回结果。 4. **异常处理**: - `TimeoutException`:如果任务在指定时间内没有完成,则抛出此异常。 - `ExecutionException`:如果任务执行过程中抛出异常,则捕获此异常,并通过`e.getCause()`获取原始异常。 - `InterruptedException`:如果当前线程在等待过程中被中断,则抛出此异常。 5. **关闭线程池**:在finally块中关闭线程池,释放资源。 ### 注意事项: - 使用`get()`方法时,一定要考虑异常处理,避免程序因未处理的异常而崩溃。 - 如果任务可能长时间运行,建议使用带超时的`get()`方法,避免永久阻塞。 - 在任务完成后,可以通过`future.isDone()`方法检查任务是否完成。 ### 相关问题: §§相关问题§§: 1. Future.get()方法在什么情况下会抛出InterruptedException? 2. 如何取消一个正在执行的Future任务? 3. 除了Future.get(),还有哪些方法可以获取异步任务的结果? 4. JavaFuture和CompletableFuture有什么区别?</think>### Java `Future.get()` 详解 `Future.get()` 是 Java 并发编程中用于获取异步任务结果的关键方法,属于 `java.util.concurrent.Future` 接口。它提供阻塞式获取结果的能力,并支持超时机制。 #### 核心特性: 1. **阻塞行为**:调用时若任务未完成,线程会阻塞等待 2. **异常传播**:任务中的异常会封装在 `ExecutionException` 中抛出 3. **超时控制**:支持设置最大等待时间 4. **中断响应**:阻塞时可响应线程中断 #### 代码示例: ```java import java.util.concurrent.*; public class FutureGetExample { public static void main(String[] args) { // 创建线程池 ExecutorService executor = Executors.newSingleThreadExecutor(); // 提交异步任务 Future<String> future = executor.submit(() -> { Thread.sleep(2000); // 模拟耗时操作 return "Task completed!"; }); try { // 1. 阻塞获取结果(无限等待) // String result = future.get(); // 2. 带超时的获取(推荐) String result = future.get(3, TimeUnit.SECONDS); System.out.println("Result: " + result); } catch (TimeoutException e) { System.err.println("Task timed out"); future.cancel(true); // 尝试取消任务 } catch (InterruptedException e) { System.err.println("Thread interrupted while waiting"); Thread.currentThread().interrupt(); // 恢复中断状态 } catch (ExecutionException e) { System.err.println("Task failed: " + e.getCause()); } finally { executor.shutdown(); } } } ``` #### 关键点解释: 1. **阻塞获取**: - 无参 `get()` 会无限期阻塞,直到任务完成 - 推荐使用带超时的 `get(long timeout, TimeUnit unit)` 2. **异常处理**: - `InterruptedException`:等待过程线程被中断 - `ExecutionException`:任务执行抛出异常(通过 `getCause()` 获取原始异常) - `TimeoutException`:超时未完成任务 3. **任务取消**: - 调用 `future.cancel(true)` 可尝试中断正在执行的任务 - `isCancelled()` 检查任务是否被取消 4. **状态检查**: - `isDone()`:检查任务是否完成(包括正常结束、取消或异常) - `isCancelled()`:检查任务是否被取消 #### 最佳实践: 1. **总是设置超时**:防止永久阻塞 2. **正确处理中断**:恢复中断状态 `Thread.currentThread().interrupt()` 3. **资源清理**:在 finally 块中关闭线程池 4. **异常处理**:通过 `ExecutionException.getCause()` 分析任务失败原因
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值