Java 多节点部署中的ArrayBlockingQueue同步
在简单的描述中,我有一个servlet,响应时间很长,所以我决定将其分为两部分,一部分只是对客户机的响应,另一部分执行一些业务逻辑并将结果存储在数据库中。为了减少响应时间,我使用Java 多节点部署中的ArrayBlockingQueue同步,java,Java,在简单的描述中,我有一个servlet,响应时间很长,所以我决定将其分为两部分,一部分只是对客户机的响应,另一部分执行一些业务逻辑并将结果存储在数据库中。为了减少响应时间,我使用ThreadPoolExecutor结合ArrayBlockingQueue异步执行业务逻辑。使用ArrayBlockingQueueI可以确保在同一客户机的请求是连续的情况下原始的FIFO顺序。这是重要的前提 以下是一个片段: Servlet public class HelloServlet extends Http
ThreadPoolExecutor
结合ArrayBlockingQueue
异步执行业务逻辑。使用ArrayBlockingQueue
I可以确保在同一客户机的请求是连续的情况下原始的FIFO顺序。这是重要的前提
以下是一个片段:
Servlet
public class HelloServlet extends HttpServlet {
AsyncExecutor exe = new AsyncExecutor();
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
PrintWriter w = resp.getWriter();
exe.executeAsync(exe.new Task(this));
w.print("HELLO TO CLIENT");
}
protected void someBusinessMethod(){
// long time execution here
}
}
执行人
public class AsyncExecutor {
static final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(10, true);
static final Executor executor = new ThreadPoolExecutor(3, 5, 20L, TimeUnit.SECONDS, queue);
public void executeAsync(Task t){
boolean isTaskAccepted = false;
while(!isTaskAccepted){
try {
executor.execute(t);
isTaskAccepted = true;
} catch (RejectedExecutionException e){
}
}
}
class Task implements Runnable{
private HelloServlet servlet;
Task(HelloServlet servlet){
this.servlet = servlet;
}
@Override
public void run() {
// just call back to servlet's business method
servlet.someBusinessMethod();
}
}
}
与第一篇文章中的实现一样,如果请求到达同一个Tomcat节点,我可以保证executeOldModelLogic方法的FIFO顺序。但由于前面有多节点部署和循环LB,我最终会遇到这样一种情况,即对于同一个调用方,“旧模型中的更新订阅”比“旧模型中的创建订阅”先到达ArrayBlockingQueue,这当然是一个糟糕的逻辑错误
至于你建议的几点:
p1、p2和p4:我可能无法将其用作解决方案,因为我没有对象的状态。您可以看到,我将Aspect和JoinPoint的引用传递给Runnable任务,以便从Runnable回调executeldmodellogic到Aspect
p3不知道这可能值得调查
p5这是我想进一步调查的方向,我直觉认为这是在给定条件下解决问题的唯一方法。有一些解决方案会马上浮现在脑海中
@Aspect @Component public class MyAspect {
@Autowired
private ApplicationContext ctx;
@Autowired
private AsyncExecutor asyncExecutor;
@Around("@annotation(executeOpi)")
public Object around(ProceedingJoinPoint jp, ExecuteOpi executeOpi) throws Throwable {
LegacyMapper newModelExecutor = ctx.getBean(executeOpi.legacyMapper());
// executes a new model and then return result in the format of old model
Object result = newModelExecutor.executeNewModelLogic(joinPoint.getArgs());
// executes old model logic asynchronously
asyncExecutor.executeAsync(asyncExecutor.new Task(this, jp)
return object
}
public void executeOldModelLogic(ProceedingJoinPoint jp) throws Throwable{
// long time execution here
jp.proceed();
}
}