当前位置: 首页 > 知识库问答 >
问题:

Java执行器获得第一个匹配条件的结果

杜弘伟
2023-03-14

当Callable返回与条件匹配的结果时,是否有一种方法可以停止Javas ExecuterService?

我有以下算法代码A):

MyObject functionA(SomeObject someObject) {
    for(int i = 0; i < 100; ++i) {
        MyObject result = someFunction(i, someObject);
        if (result != null) {
            return result;
        }
    }
    return null;
}
MyObject functionB(SomeObject someObject) {
    final ExecutorService executorService = Executors.newCachedThreadPool();
    List<Callable<MyObject>> callableList = new ArrayList<Callable<MyObject>>();
    for(int i = 0; i < 100; ++i) {
        final int finalI = i;
        Callable<MyObject> newCallable = () -> {
            return someFunction(finalI, someObject);
        };
        callableList.add(newCallable);
    }
    List<Future<MyObject>> futures = executorService.invokeAll(callableList);
    for(int i = 0; i < futures.size(); ++i) {
        Future<MyObject> future = futures.get(i);
        if(future.get() != null) {
            return future.get();
        }
    }
    return null;
}

平均而言,functionB的运行速度是functionA的5倍(在8个内核上)。

这很好,但不完美。在functionA中,someFunction()在找到结果!=null之前平均被调用大约20次。在functionB中,someFunction()总是被调用100次。

有没有办法

或更好

b)停止executorService,当一个线程完成并且一个线程找到了结果!=null,并且所有线程的finalI值都低于找到结果的线程!=null,都用reuslt==null完成

谢谢

------编辑--------

感谢Alex Crazy和Saxon的回答,我能够回答我的问题A。

    null
MyObject functionC(SomeObject someObject) {
    final ExecutorService executorService = Executors.newFixedThreadPool(8);
    List<Callable<MyObject>> callableList = new ArrayList<Callable<MyObject>>();
    for(int i = 0; i < 100; ++i) {
        final int finalI = i;
        Callable<MyObject> newCallable = () -> {
            MyObject result = someFunction(finalI, someObject);
            if(result == null) {
                throw new Exception();
            }
            return result;
        };
        callableList.add(newCallable);
    }
    try {
        MyObject result = executorService.invokeAny(callableList);
        return result;
    } catch (InterruptedException | ExecutionException e) {
        return null;
    }
}

所以我编写了新类ResultCallable

public abstract class ResultCallable<E>  implements Callable<E> {
    E result = null;
}

和函数d

MyObject functionD(SomeObject someObject) {
    final ExecutorService executorService = Executors.newFixedThreadPool(8);
    List<Callable<MyObject>> callableList = new ArrayList<Callable<MyObject>>();
    for(int i = 0; i < 100; ++i) {
        final int finalI = i;
        ResultCallable<MyObject> newCallable = () -> {
            this.result = someFunction(finalI, someObject);
            if(this.result == null) {
                throw new Exception();
            }
            return this.result;
        };
        callableList.add(newCallable);
    }
    try {
        MyObject result = executorService.invokeAny(callableList);
        executorService.shutdownNow();
        executorService.awaitTermination(5, TimeUnit.SECONDS);
        for(int i = 0; i < callableList.size(); ++i) {
            if(callableList.get(i).result != null) {
                return callableList.get(i).result;
            }
        }
    } catch (InterruptedException | ExecutionException e) {
        return null;
    }
    return null;
}

如果SomeFunction(3,someObject)SomeFunction(6,someObject)将返回一个非空的MyObject对象,那么主线程将在第一个有效结果之后等待所有其他已启动的任务完成(使用newFixedThreadPool(8)最多有7个其他任务正在运行)。因为executorService按callableList中的顺序运行调用项,所以finalI值低于返回第一个有效结果的callable的所有调用项都已启动,并将在第19行之前完成。

这很好,但并不完美。
假设finalI=6的任务首先完成,并且finalI从0到5和7的任务仍在运行。然后因为ExecutorService.ShutdownNow();不会启动其他任务,主线程将等待所有正在运行的任务完成。
但我只需要等待finalI介于0和3之间的任务完成。任务3,因为它还有一个结果!=null和任务0、1和2来证明任务3下面没有结果。

我可以用下面这样的东西替换ExecutorService.AwaitTermination和for循环吗?

for(int i = 0; i < callableList.size(); ++i) {
    awaitTermination(callableList.get(i));
    if(callableList.get(i).result != null) {
        return callableList.get(i).result;
    }
}

AwaitTermination(CallableList.Get(i));是伪代码。我找不到一个函数等待一个可调用的执行。

----------------编辑2-----------------------

我自己解决的。

如果你有更好的主意,让我知道。

共有1个答案

东方弘壮
2023-03-14

为什么不使用invokeAny而不是InvokeAll。在结果不好时抛出一个异常而不是返回null,在ExecutorService调用上返回MyObject而不是List 就足够了。

 类似资料:
  • 如何在流中获得第一个匹配条件的元素?我试过了,但不起作用 如果条件不起作用,则在Stop以外的其他类中调用filter方法。

  • 我有一个接口,它提供了一个方法,返回一个,其中包含一个

  • 我正在尝试使用获取每个页面的第一个链接,但是,这个代码获取所有页面的数据,然后多次打印第一个页面的链接。 我做错了什么? 编辑: 让我用另一种方式解释:我有5个html页面,每个html页面包括10个链接,我想要每个html页面的第一个链接。 所以我使用jQuery脚本提取href属性值,它是链接,但是,它不是提取每个页面的第一个链接,而是提取第一个页面的第一个链接5次,因为我有5个文件。

  • 问题内容: 我正在尝试匹配模式: 以下仅匹配第一次出现的情况: 结果是: 但是,[使用pythex似乎可以正常工作](http://pythex.org/?regex=%3C–(%5B%5Cw%5Cs%5D%2B)–%3E(%5B%5Cs%5CS%5D*%3F)(%3F%3D%5Cn%3C–%7C%24)&test_string=%3C–%20Option%201%20–%3E%0ANice%20

  • 问题内容: 这将更好地显示在我的示例中: 我有一张桌子,存储着用户从一种大表格中得到的答案。每个表格有139个问题。这些问题存储在不同的表中,并在需要时与questionID结合在一起。对于每个用户,都有一个ID。现在,我需要进行过滤,以仅显示与特定问题匹配一个或 多个 答案的用户。 例如,我希望用户在问题14中回答为“是”,问题54不为空且问题100大于10的情况下。表的外观如下: 结果,我只希

  • 你好,我在Java中使用正则表达式时遇到了一个问题。 我试图解析这个: 使用此代码(模式匹配器) 我的问题是,我的regexp只返回模式的第一次出现,即使我有一段时间(matcher.find())。。