【问题标题】:achieving Synchronized behavior with ThreadPoolExecutor using SynchronousQueue使用 SynchronousQueue 与 ThreadPoolExecutor 实现同步行为
【发布时间】:2020-07-23 18:49:42
【问题描述】:

我正在编写一个服务类,它应该有两种模式:同步和异步。

public class ProcessorImpl implements IProcessor {

    private final MyRepo repo;
    private final Jobrunner runner;
    private final boolean isAsync;


    private ExecutorService executorService;

    @ProcessorImpl
    public ProcessorImpl(final MyRepo repo,
                              final Jobrunner runner) {
        this(repo, runner, false);
    }

    public ProcessorImpl(final MyRepo repo,
                              final Jobrunner runner,
                              final boolean isAsync) {
        this.repo = repo;
        this.runner = runner;
        this.isAsync = isAsync;
    }

    @PostConstruct
    public void init() {
        if (isAsync) {          
            executorService = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(50));
        } else {
            executorService = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS, new SynchronousQueue<>());
        }
    }

    @Override
    public Response doAction(final Request request, final String id) {
        if (isAsync) {
            //submit task and return incomplete response with id
        } else {
            //submit task and get result and return response that is returned by Callable
        }
    }
}

切换由isAsync 标志驱动。

当同步时,我希望能够提交任务,从任务提交中获取完成的响应并使用它来构建Response 以返回。对于这种模式,我使用的是SynchronousQueue

当异步模式开启时,只需提交任务并立即返回,响应不完整。对于这种模式,我使用LinkedBlockingQueue来等待队列中的任务。

关于同步模式,我有两个问题:

  1. 如何获取结果并以同步方式给出响应?我不确定如何在这里使用Future

  2. 如果线程正在处理任务时另一个命令任务进来怎么办?会被拒绝吗?如何避免被拒绝?

对于一些代码示例的任何帮助将不胜感激。

谢谢

【问题讨论】:

  • 你不怕RejectedExecutionExceptionnew ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS, new SynchronousQueue&lt;&gt;())吗?
  • @akuzminykh 实际上我的第二个问题是关于如何在命令来得快​​于处理速度时避免这种情况。这些doAction都是由Rest调用请求/响应发起的,有些想要完整的结果,有些可以不完整,稍后再查询。
  • 你可以例如使用this 构造函数并给它ThreadPoolExecutor.CallerRunsPolicy,它只会让调用者执行任务。还有更多。你甚至可以自己实现一个。
  • 好的,看看一个例子就好了。如果在这个主线程中我正在做Future. get() 调用等待第一个命令的结果,有什么问题吗?
  • 我不会使用 isAsync 标志。我会做2个不同的课程。 SyncProcessorImpl 的 doAction 方法返回 Future,ASyncProcessorImpl 的 doAction 方法返回 Response 并直接进行所有计算,无需线程池。

标签: java spring multithreading concurrency thread-safety


【解决方案1】:

类似这样的:

public class SyncProcessorImpl {
    private final MyRepo repo;
    private final Jobrunner runner;

    public SyncProcessorImpl (final MyRepo repo, final Jobrunner runner) {
        this.repo = repo;
        this.runner = runner;
    }

    public Response doAction(final Request request, final String id) {
        // do all calculations directly and return complete response
    }
}

public class AsyncProcessorImpl extends SyncProcessorImpl {
    private ExecutorService executorService;

    public AsyncProcessorImpl(final MyRepo repo, final Jobrunner runner) {
        super(repo, runner);
        executorService = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(50));
    }

    public Future<Response> doActionAsync(final Request request, final String id) {
        //submit task and return future that is returned by submit(Callable)
       return executorService.submit(()->super.doActionc(request, id));
    }
}

【讨论】:

  • 谢谢,因为这是框架,它需要支持你的答案给出的两种实现。但是,在其类路径中具有此功能的其他项目应该能够选择哪种模式,同步或异步 bean..这是我正在努力解决的问题,因此 isAsync 标志
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-27
  • 2014-01-17
  • 2017-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多