Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java J2EE环境-多线程-并行从不同服务获取数据_Java_Multithreading_Performance_Jakarta Ee_Design Patterns - Fatal编程技术网

Java J2EE环境-多线程-并行从不同服务获取数据

Java J2EE环境-多线程-并行从不同服务获取数据,java,multithreading,performance,jakarta-ee,design-patterns,Java,Multithreading,Performance,Jakarta Ee,Design Patterns,除了我在下面使用的内容,还有其他更好的选择(设计/性能/内存优化)吗 问题陈述:在J2EE环境中,当收到请求时,我的控制器需要从三个不同的服务获取数据(例如,第一个获取天气数据,第二个获取流量密度,最后一个获取当前访问我们的外星人数量)。如果一个服务需要5秒(最好是5秒)来获取,那么以同步方式,它们至少需要15秒。但控制器的运行时间不应超过6-7秒。因此,最终调用不同的线程。但在某些情况下,服务所需时间可能超过10秒(可能是最坏的情况) 所以我考虑创建一个线程等待,通知,使用一个可观察的模式,并

除了我在下面使用的内容,还有其他更好的选择(设计/性能/内存优化)吗

问题陈述:在J2EE环境中,当收到请求时,我的控制器需要从三个不同的服务获取数据(例如,第一个获取天气数据,第二个获取流量密度,最后一个获取当前访问我们的外星人数量)。如果一个服务需要5秒(最好是5秒)来获取,那么以同步方式,它们至少需要15秒。但控制器的运行时间不应超过6-7秒。因此,最终调用不同的线程。但在某些情况下,服务所需时间可能超过10秒(可能是最坏的情况)

  • 所以我考虑创建一个线程等待,通知,使用一个可观察的模式,并保持一个小的状态。它在工作,但并不快乐 与设计

  • 然后我找到了Java“ForkJoinPool”。对于每个请求,控制器都会创建一个新的“
    ForkJoinPool
    ”实例-现在不会在每个请求上创建它。创建一个自定义 类(比如说
    ForkService
    )扩展具有
    列表
    。ForkService的计算方法


  • 目前正在使用此功能,并且性能良好。想知道有更好的方法吗?

    一个简单而优雅的方法是使用固定线程池和番石榴,您可以调用:

    private MyResult getResult(MyRequest){
    Executors服务es=Executors.newFixedThreadPool(3);
    ListingExecutorService les=更多执行者ListingDecorator;
    ListenableFuture lf1=les.submit(GetCallableForService 1(请求));
    ListenableFuture lf2=les.submit(getCallableForService2(请求));
    ListenableFuture lf3=les.submit(getCallableForService3(request));
    ListenableFuture res=lfs.get(7,TimeUnit.SEONDS);
    返回提取器(res);
    }
    

    当然,您应该为
    可调用的
    处理正确的类型。

    我不太熟悉,但我可以马上告诉您,为每个请求创建一个新的线程池会破坏线程池的一半功能。创建和销毁线程的成本很高,使用线程池可以重用线程

    看一下文档,Fork/Join似乎是为那些本质上是递归的、需要密集处理的问题而设计的。你的问题似乎不符合这两个标准

    您最好使用所有请求共享的常规服务。这种方法可能会特别有用;您可以一次提交所有3个请求,接收
    列表
    ,如果愿意,甚至可以提供超时

    要获得结果,只需在
    列表上循环:

    Thing[] results = new Thing[3];
    for (int i = 0; i < things.size(); ++i) {
        results[i] = things.get(i).get();
    }
    
    Thing[]results=新事物[3];
    for(int i=0;i
    已经有一段时间了,但考虑过写下其他选项:
    1.回调的使用。当线程完成工作时,它会通过回调进行响应。
    2.通知:每个线程在工作完成时发送通知。
    3.使用问题中提到的
    RecursiveAction


    4.答案被接受为最终答案,其中使用了番石榴图书馆的
    ListenableFuture

    当您应该使用任务并行时,您正在使用数据并行。核心Java中没有任务并行框架,因此Jean Logeart有一个很好的解决方案。正如@Floegipoky所指出的,每次创建/销毁框架都很糟糕。如果你可以使用外部产品,那么我可以引导你朝这个方向发展。谢谢@Floegipoky的建议。现在它只是一个实例。问题是如何停止接收请求的主事件循环/线程!我不想分秒必争地查看是否所有服务都已响应。这就是我在第一个解决方案中尝试使用observable模式的原因,在该模式中,observable通知他们是否成功。在JavaEE环境中,您应该使用ManagedExecutorService,而不是JavaSE ExecutorService。使用@Resource注入ManagedExecutorService的实例。
    private MyResult getResult(MyRequest request) {
        ExecutorService es = Executors.newFixedThreadPool(3);
        ListeningExecutorService les = MoreExecutorslisteningDecorator(es);
    
        ListenableFuture<?> lf1 = les.submit(getCallableForService1(request));
        ListenableFuture<?> lf2 = les.submit(getCallableForService2(request));
        ListenableFuture<?> lf3 = les.submit(getCallableForService3(request));
        ListenableFuture<List<?>> lfs = Futures.successfulAsList(lf1, lf2, lf3);
    
        // wait 7 sec for results
        List<?> res = lfs.get(7, TimeUnit.SEONDS);
    
        return extractRes(res);
    }
    
    Thing[] results = new Thing[3];
    for (int i = 0; i < things.size(); ++i) {
        results[i] = things.get(i).get();
    }