启动多个线程并收集结果

时间:2019-06-17 15:11:12

标签: java multithreading

我有一个接口,用于搜索由ENUM收集的某些子系统。界面如下:

public interface ReferenceController {

    public Map<String, ReferenceElement> searchElements(String searchField, List<String> searchItems, SystemStage systemStage) throws Exception;

    public Boolean isAvailable(SystemStage systemStage) throws Exception;

    public Boolean isAvailable(SystemStage systemStage) throws Exception;
}

ENUM看起来像这样

public enum ReferenceSystem implements ReferenceController{
    UCMDB    (UcmdbFunctions.class),
    PROIPS   (ProIPSFunctions.class),
    KV       (KvFunctions.class),
    FISERVICE(FiServiceFunctions.class),
    COMMAND  (CommandFunctions.class),
    FII          (FiiFunctions.class);

    private Class<? extends ReferenceController> clazz;

    private ReferenceSystem(Class<? extends ReferenceController> controllerClass) {
        this.clazz = controllerClass;
    }

    public String displayName() {
        return displayName(Locale.GERMAN); 
    }

    public String displayName(Locale locale) {
        ResourceBundle bundle = ResourceBundle.getBundle("EnumI18n", locale);
        return bundle.getString(toString()); 
    }

    public Class<? extends ReferenceController> getClassname() { return clazz; }

    @Override
    public Map<String, ReferenceElement> searchElements(String searchField, List<String> searchItems, SystemStage systemStage) throws Exception {
        Map<String, ReferenceElement> result = clazz.newInstance().searchElements(searchField, searchItems, systemStage);
        return result;
    }

    @Override
    public String getStateMapping(String value) {
        try {
            return clazz.newInstance().getStateMapping(value);
        } catch (IllegalAccessException | InstantiationException e) {
            return null;
        }
    }

    @Override
    public Boolean isAvailable(SystemStage systemStage) throws Exception {
        return clazz.newInstance().isAvailable(systemStage);
    }
}

此刻,我一个接一个地开始搜索。因此,我的服务器不必等待搜索完成才可以开始下一个搜索。因此,用户必须非常等待语言才能呈现结果。 这段代码开始搜索

    public static void performSingleSearch(ReferenceSystem referenceSystem, String searchField, List<String> searchValues, SystemStage systemStage) throws Exception {

        if(!isAvailable(referenceSystem, systemStage)) return;
        Map<String, ReferenceElement> result = new HashMap<>();
        try {
            result = referenceSystem.searchElements(searchField, searchValues, systemStage);
        } catch (Exception e) { 
            return;
        }
        if(result != null) orderResults(result, referenceSystem);
    }

resultmap是所有子系统的相同对象,因此我需要一个系统,该系统可以立即开始所有搜索并将其结果放入结果对象。

我希望可以几乎同步地填充那些对象,从而使用户不必等待所有系统完成。

最好的问候 丹尼尔

1 个答案:

答案 0 :(得分:0)

如果您愿意使用Guava,则可以使用ListeningExecutorService.submit提交Callable,将每个调用包装到searchElements并在其中收集返回的ListenableFuture实例一个列表。使用Futures.allAsList可以将列表转换为Future,如果所有Future成功完成,则返回所有结果的列表,否则,则完成失败。

例如:

<T> void submitAll(
        Collection<Callable<T>> callables,
        Consumer<List<T>> onSuccess,
        Consumer<Throwable> onError,
        ExecutorService executor) {

    ListeningExecutorService decoratedExecutor = MoreExecutors.listeningDecorator(executor);

    List<ListenableFuture<T>> futures = Lists.newArrayList();
    for (Callable<T> callable : callables) {
        futures.add(decoratedExecutor.submit(callable));
    }

    FutureCallback<? super List<T>> cb = new FutureCallback<List<T>>() {
        public void onSuccess(List<T> result) {
            onSuccess.accept(result);
        }

        public void onFailure(Throwable t) {
            onError.accept(t);
        }
    };

    Futures.addCallback(Futures.allAsList(futures), cb, executor);
}