Java future get()方法如何处理超时

Java future get()方法如何处理超时,java,Java,我有点困惑Future.get(timeout)是如何按照定义工作的,它将在指定的超时时间后通过异常,但它不会发生在我的测试用例中 import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import

我有点困惑Future.get(timeout)是如何按照定义工作的,它将在指定的超时时间后通过异常,但它不会发生在我的测试用例中

import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class CallableExample {

public static class WordLengthCallable implements Callable<String> {
    private String word;
    private long waiting;

    public WordLengthCallable(String word, long waiting) {
        this.word = word;
        this.waiting = waiting;
    }

    public String call() throws InterruptedException {
        Thread.sleep(waiting);
        return word;
    }
}

public static void main(String args[]) throws Exception {
    args = new String[] { "i", "am", "in", "love" };
    long[] waitArr = new long[] { 3000, 3440, 2500, 3000 };
    ExecutorService pool = Executors.newFixedThreadPool(3);
    Set<Future<String>> set = new LinkedHashSet<Future<String>>();
    int i = 0;
    for (String word : args) {
        Callable<String> callable = new WordLengthCallable(word, waitArr[i++]);
        Future<String> future = pool.submit(callable);
        set.add(future);
    }
    String sum = "";
    for (Future<String> future : set) {
        try {
            sum += future.get(2000, TimeUnit.MILLISECONDS) + ", ";
        } catch (Exception e) {
        }
    }
    System.out.print("Result : " + sum);
}
}
import java.util.LinkedHashSet;
导入java.util.Set;
导入java.util.concurrent.Callable;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
导入java.util.concurrent.TimeUnit;
公共类可调用示例{
公共静态类WordLengthCallable实现了Callable{
私有字符串字;
私人长时间等待;
public WordLengthCallable(字符串字,长等待){
这个单词=单词;
这就是等待;
}
公共字符串调用()引发InterruptedException{
睡眠(等待);
返回词;
}
}
公共静态void main(字符串args[])引发异常{
args=新字符串[]{“我”、“我”、“在”、“爱”};
long[]waitArr=新的long[]{3000344025003000};
ExecutorService池=Executors.newFixedThreadPool(3);
Set Set=newlinkedhashset();
int i=0;
for(字符串字:args){
Callable Callable=新单词lengthCallable(单词,waitArr[i++]);
Future=pool.submit(可调用);
集合。添加(未来);
}
字符串sum=“”;
for(未来:集合){
试一试{
sum+=future.get(2000,TimeUnit.ms)+“,”;
}捕获(例外e){
}
}
系统输出打印(“结果:+sum”);
}
}
输出“am,in,”


它在更改数组中的等待时间(timeArr值)时的行为不同。何时使用带超时的get?

在for循环中,您等待第一个将来完成。这可能需要2000毫秒。此时,所有其他线程都将休眠。因此,其他线程的所有值都小于2000毫秒。然后你再等待2000毫秒,也许你等待的是未来的回报。因此,两个或多个线程将成功

在循环的每次迭代中,您都会向另一个线程提供2000毫秒。只有当一个期货成功回归时,你才能减少对剩余期货的捐赠。如果您希望观察到由于2000毫秒超时而导致的所有未来失败,那么您还必须并行处理它们

如果以这种方式更改某些代码:

Set<Callable<String>> tasks = new HashSet<>();
for (String word : args) {
    tasks.add(new WordLengthCallable(word, waitArr[i++]));
}
List<Future<String>> futures = Executors.newFixedThreadPool(3)
        .invokeAll(tasks, 2000, TimeUnit.MILLISECONDS);

对于每个创建的
可调用的
,它们都大于2000。

编辑:感谢@RQube提醒我线程的执行顺序为3。螺纹将在1,4之前完成。线程将在3'完成后开始,而不是1'完成后开始

首先,线程池的大小是3。这意味着你的4。未来将等待3。结束

让我们假设除了线程等待之外没有其他耗时的工作。执行过程如下:

  • 未来-3000ms等待时间-这将引发超时异常,但会继续运行,因为您不会在超时时终止它。所以你的4。未来仍在等待一个线程完成。 总执行时间:2000ms

  • 未来-1440ms等待,因为您已经等待了2000ms-这将返回您在输出“am”中看到的结果。也在2500ms标记3处。未来将被执行和4。未来将在2500毫秒标记处开始。 总执行时间:3440ms

  • 未来-没有等待时间,因为我们已经等待3440毫秒,这将立即返回。 总执行时间:3440ms

  • 未来-2060毫秒等待时间完成,因为这已在2500毫秒标记处启动,并且在启动940毫秒后已通过。这将在2000ms后超时(等待时间为2940ms)

  • 正如你所看到的2。三,。当您调用get()时,Futures将返回,但实际上它们都已执行


    很抱歉,我在手机上写东西时出现了格式错误和打字错误。

    根据您的描述,执行过程非常相似,但为什么上一个任务的等待时间为3000毫秒,请说明原因。明白了,第四个任务的执行将在2500ms后开始,在未来第四轮时,它将完成3440-2500=940ms的睡眠时间,但仍需要2060ms的时间才能完成,导致超时:)感谢时间,经过几次研发,在@Harmlez的帮助下,我了解了该场景。这与您的描述完全相同,但第四个任务将在前三个任务中等待时间最短的任务之一完成时开始。由于第三个任务的最小等待时间为2500ms,因此第四个任务将在2500ms后启动,而不是3000ms。
    3000, 3440, 2500, 3000