如何使用spring并行执行多个数据库调用?

时间:2017-08-22 17:31:50

标签: java spring multithreading java-8 completable-future

我正在尝试提高弹簧应用程序的性能,调用大约8-10个查询,并且它将需要大约15到120秒,具体取决于它查询的数据量,我提出了CompletableFuture /在Java 8中实现它的未来方式。但是,我一直停留在主线程不等待异步线程完成的位置。以下是我到目前为止实施的代码。

我打算使用未来'回去实施它。和ThreadPoolExecutor并有一个线程,等待threadPoolExecutor中生成的可调用线程的完成返回数据。

问题:在java中实现CompletableFuture的任何简单方法,主线程在将数据返回给客户端之前等待线程池中的所有线程完成?

InvokeCallable .java

package net.sampleSpring.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;

@Component
public class InvokeCallable {

    @Autowired
    private ApplicationContext context;

//    @Autowired
//    @Qualifier("threadPoolExecutor")
//    private ThreadPoolTaskExecutor executorThreadPool;


    public void invokeCallables() throws InterruptedException, ExecutionException {
        List<CompletableFuture<Integer>> lst = new ArrayList<>();
        CallableOne callableOne = context.getBean(CallableOne.class);
        CallableTwo callableTwo = context.getBean(CallableTwo.class);

        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
                                                                                          @Override
                                                                                          public Integer get() {
                                                                                              try {
                                                                                                  return callableOne.call();
                                                                                              } catch (Exception e) {
                                                                                                  e.printStackTrace();
                                                                                              }
                                                                                              return 1;
                                                                                          }
                                                                                      }
        );

        CompletableFuture<String> completableFuture2 = CompletableFuture.supplyAsync(new Supplier<String>() {
                                                                                         @Override
                                                                                         public String get() {
                                                                                             try {
                                                                                                 return callableTwo.call();
                                                                                             } catch (Exception e) {
                                                                                                 e.printStackTrace();
                                                                                             }
                                                                                             return "1";
                                                                                         }
                                                                                     }
        );

        CompletableFuture.allOf(completableFuture1, completableFuture2).thenApply(
                i -> {
                    System.out.println("Completed running the futures");
                    System.out.println("future 1" + completableFuture1.join().toString());
                    System.out.println("future 2" + completableFuture2.join().toLowerCase());
                    return i;
                }
        );

    }
}

CallableTwo.java

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.concurrent.Callable;

@Component
@Scope("prototype")
public class CallableTwo {

    public String call() throws Exception {
        Thread.sleep(2000);
        return "1000";
    }
}

CallableOne.java

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class CallableOne {

    public Integer call() throws Exception {
        Thread.sleep(2000);
        return 1;
    }
}

sampleSpringResource.java 使用restful服务调用InvokeCallable.java的代码

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

import java.util.concurrent.ExecutionException;

import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.json.XMLTokener.entity;

/* ItemValue Web service
 *
 */
@Path("/")
@Service
public class sampleSpringResource {

    @Inject
    private InvokeCallable callable;

    private static final Logger LOG = LogManager.getLogger();

    @GET
    @Path("/changeme/")
    @Produces(APPLICATION_JSON)
    public Response getsampleSpring() throws ExecutionException, InterruptedException {            
        callable.invokeCallables();               

    }

}

1 个答案:

答案 0 :(得分:0)

感谢Abhijit指向正确的位置。我已经按照以下方式实现了它。

<强> SampleSpringResourc.java

/* ItemValue Web service
 *
 */
@Path("/")
@Service
public class sampleSpringResource {

    @Inject
    private InvokeCallable callable;

    private static final Logger LOG = LogManager.getLogger();


    @GET
    @Path("/changeme/")
    @Produces(APPLICATION_JSON)
    public Response getsampleSpring() throws ExecutionException, InterruptedException {
        System.out.print("In getSampleSpring()..");
        try {
            callable.invokeCallables();
            System.out.println("returning from the result");
            return LOG.exit(Response.status(Response.Status.OK).entity("Success").build());
        } catch (DataAccessException ex) {
            return LOG.exit(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(new ServiceError(ErrorCode.INTERNAL_SERVER_ERROR, ex.getMessage())).build());
        } catch (Exception ex) {
            return LOG.exit(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(new ServiceError(ErrorCode.INTERNAL_SERVER_ERROR, ex.getMessage())).build());
        }

    }

}

<强> InvokeCallable

@Component
public class InvokeCallable {

    @Autowired
    private ApplicationContext context;

    @Autowired
    private CallableTwo callableTwo;

    @Autowired
    private CallableOne callableOne;

    public void invokeCallables() throws Exception {
        List<CompletableFuture<Integer>> lst = new ArrayList<>();
        System.out.println("Callable one start " + new Date());
        CompletableFuture<Integer> completableFuture1 = callableOne.call();
        System.out.println("Callable one end " + new Date());

        System.out.println("Callable two start " + new Date());
        CompletableFuture<String> completableFuture2 = callableTwo.call();
        System.out.println("Callable two end " + new Date());

        CompletableFuture.allOf(completableFuture1, completableFuture2).join();
        System.out.println("Completable future all end " + new Date());
    }
}

<强> CallableTwo

@Component
@Scope("prototype")
public class CallableTwo {

    @Async
    public CompletableFuture<String> call() throws Exception {
        Thread.sleep(2000);
        return CompletableFuture.completedFuture("1000");
    }
}

<强> CallableOne

@Component
@Scope("prototype")
public class CallableOne {

    @Async
    public CompletableFuture<Integer> call() throws Exception {
        Thread.sleep(2000);
        return CompletableFuture.completedFuture(1);
    }
}

下面的日志显示了两个线程的合并时间结果。每个线程大约需要2秒钟。

<强>日志

2017-08-23 11:27:30,118 INFO  [stdout] (default task-4) In getSampleSpring()..Callable one start Wed Aug 23 11:27:30 CDT 2017

2017-08-23 11:27:30,124 INFO  [stdout] (default task-4) Callable one end Wed Aug 23 11:27:30 CDT 2017

2017-08-23 11:27:30,125 INFO  [stdout] (default task-4) Callable two start Wed Aug 23 11:27:30 CDT 2017

2017-08-23 11:27:30,126 INFO  [stdout] (default task-4) Callable two end Wed Aug 23 11:27:30 CDT 2017

2017-08-23 11:27:32,138 INFO  [stdout] (default task-4) Completable future all end Wed Aug 23 11:27:32 CDT 2017

2017-08-23 11:27:32,138 INFO  [stdout] (default task-4) returning from the result