有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java中的tomcat异步

我有一些代码:

1-通过REST呼叫(POST)接收到一些数据

2-根据该数据执行一些逻辑

3-返回结果

为了回答这个问题,让我们假设它是一个简单的计算器webapi,它允许客户端执行加法和减法运算。看起来是这样的:

@Path("/calculator")
public class Calculator {

    @POST
    @Path("addition")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response add(String request){
        //Getting A and B from request
        ...
        //Calculating result
        int res = a + b;
        //Creating response payload
        JSONObject res = new JSONObject.put("result",res);

        return Response.status(Response.Status.OK).entity(res.toString()).build();
    }

    @POST
    @Path("subtract")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response sub(String request){
        //Getting A and B from request
        ...
        //Calculating result
        int res = a - b;
        //Creating response payload
        JSONObject res = new JSONObject.put("result",res);

        return Response.status(Response.Status.OK).entity(res.toString()).build();
    }
}

一切都很好,直到我意识到我不能并行执行多个计算,因为所有请求都访问了一个唯一的资源,一次只能由其中一个使用

因此,在本例中,让我们假设只有一个计算器,所有请求的计算都必须由同一个计算器处理器执行

在我看来,我需要一个类似“CalculatorProcessor”的东西,它接收来自所有calculator webapi客户端的请求,这些客户端:

1-接收请求

2-排队请求

3-要求排队

4-执行计算

5-使用回调返回结果

对于我来说,这在本机Java中有点微不足道,但对于如何在Java Jersey的上下文中实现这一点,我没有任何线索。 例如。。。 我怎样才能回到计算器。add()和计算器。sub()方法,以便发送http请求响应? 有人能告诉我吗

下面是我对此类组件的java实现:

import java.util.concurrent.ConcurrentLinkedQueue;

//IMPLEMENTS SINGLETON PATTERN
public class Calculator {

private static Calculator instance = null;
private ConcurrentLinkedQueue<Request> queue = null;
private Runnable processor = null;

//PRIVATE CONSTRUCTOR
private Calculator() {
    queue = new ConcurrentLinkedQueue<>();
}

//GET CALCULATOR INSTANCE
static public Calculator getInstance() {
    if (instance == null) {
        instance = new Calculator();
    }
    return instance;
}

//REQUEST COMPUTATION
public synchronized void requestComputation(CalculatorCallback c, SupportedOperations o, int a, int b) {
    //Adds request to queue
    queue.add(new Request(c, o, a, b));

    //Checks if there's an active processor
    if (processor == null) {
        //Launches a new processor if there isn't
        Runnable p = new CalculatorProcessor(queue);
        new Thread(p).start();
    }
}

//CALLBACK INTERFACE
public interface CalculatorCallback {
    void computationReady(int result);
}


//SUPPORTED OPERATIONS ENUMERATION
protected enum SupportedOperations {
    ADDITION, SUBTRACTION;
}

//CLASS THAT REPRESENTS A REQUEST
private class Request {

    final SupportedOperations operation;
    final CalculatorCallback callback;
    final int a;
    final int b;

    public Request(CalculatorCallback c, SupportedOperations operation, int a, int b) {
        this.callback = c;
        this.operation = operation;
        this.a = a;
        this.b = b;
    }
}

//CALCULATOR PROCESSOR THREAD
class CalculatorProcessor implements Runnable {

    final private ConcurrentLinkedQueue<Calculator.Request> queue;

    public CalculatorProcessor(ConcurrentLinkedQueue<Calculator.Request> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        Calculator.Request current;
        int result;
        while (!queue.isEmpty()) {
            //Gets head
            current = queue.poll();

            if (current.operation == Calculator.SupportedOperations.ADDITION) {
                result = current.a + current.b;
            } else if (current.operation == Calculator.SupportedOperations.SUBTRACTION) {
                result = current.a - current.b;
            } else {
                throw new UnsupportedOperationException();
            }
            //Calls back the requester
            current.callback.computationReady(result);
        }
    }
}
}

以下是CalculatorClient代码:

public class CalculatorClient implements Calculator.CalculatorCallback {

public static void main(String[] args) {

    CalculatorClient client = new CalculatorClient();
    Random random = new Random();
    int a, b;

    for (int i = 0; i < 1000; i++) {
        a = random.nextInt(Integer.MAX_VALUE/2);
        b = random.nextInt(Integer.MAX_VALUE/2);
        System.out.println("Requesting "+a+" + "+b+"...");
        Calculator.getInstance().requestComputation(client, Calculator.SupportedOperations.ADDITION,a,b);
    }
}

@Override
public void computationReady(int result) {
    System.out.println("Result is: "+result);
}

}


共 (1) 个答案

  1. # 1 楼答案

    如果你使用的是Jersey 2,你可以使用它的Asynchronous processing feature。您只需将AsyncResponse传递给计算任务,当处理完成时,任务将只resume响应

    @POST
    public void add(@Suspended AysncResponse response, String body) {
        Calculator.getInstance().requestComputation(
                client, 
                Calculator.SupportedOperations.ADDITION,
                a,b,
                response);
    
        // you don't need to return anything from the resource method
        // calling `response.resume(someResponse)` (from inside the task)
        // is enough. That is why this method just returns `void`
    }
    

    使用异步功能的好处是,如果处理需要很长时间,就不会像尝试使用倒计时锁存器或阻塞队列之类的阻塞机制那样阻塞服务器线程。服务器线程会立即返回到服务器,以便它可以处理更多请求