简体   繁体   English

Java - 使用通用执行程序服务实例进行并发处理

[英]Java - Concurrent processing with a common executor service instance

I have n number of worker threads that retrieve records from a kinesis stream (this is not important for this problem), which are then pushed on to an executor service where the records are processed and persisted to a backend database.我有 n 个工作线程从 kinesis 流中检索记录(这对于这个问题并不重要),然后将其推送到执行程序服务,在该服务中记录被处理并保存到后端数据库。 This same executor service instance is used for all worker threads.这个相同的执行程序服务实例用于所有工作线程。

Now there is a scenario where any given worker loop stops processing records and blocks until all records that were submitted by it are processed completely.现在有一个场景,任何给定的工作循环停止处理记录并阻塞,直到提交所有记录都被完全处理。 This essentially means that there should be no pending/running threads in the executor service for a record from that particular worker thread.这实质上意味着对于来自该特定工作线程的记录,执行程序服务中不应该有挂起/正在运行的线程。

A very trivial example of the implementation is like this:一个非常简单的实现例子是这样的:

  1. Worker class工人阶级

    public class Worker { Worker(Listener listener){ this.listener = listener; } //called periodically to fetch records from a kinesis stream public void processRecords(Record records) { for (Record record : records) { listener.handleRecord(record); } //if 15 minutes has elapsed, run below code. This is blocking. listener.blockTillAllRecordsAreProcessed() }

    } }

  2. Listener class监听类

    public class Listener { ExecutorService es; // same executor service is shared across all listeners. Listener(ExecutorService es){ this.es = es; } public void handleRecord(Record record) { //submit record to es and return // non blocking } public boolean blockTillAllRecordsAreProcessed(){ // this should block until all records are processed // no clue how to implement this with a common es } }

The only approach I could think of is to have a local executor service for each worker and do something like invokeAll for each batch, which would be change the implementation slightly but get the job done.我能想到的唯一方法是为每个工作人员提供一个本地执行程序服务,并为每个批次执行诸如invokeAll的操作,这将稍微更改实现但完成工作。 but I feel like there should be a better approach to tackle this problem.但我觉得应该有更好的方法来解决这个问题。

You could use the CountdownLatch class to block as follows:您可以使用 CountdownLatch 类来阻止,如下所示:

public void processRecords(List<Record> records) {
 CountDownLatch latch = new CountDownLatch(records.size());
 for (Record record : records) {
     listener.handleRecord(record, latch);
 }

 //if 15 minutes has elapsed, run below code. This is blocking.
 listener.blockTillAllRecordsAreProcessed(latch)
 } 

public class Listener {
 ExecutorService es;
 ...
 public void handleRecord(Record record, CountDownLatch latch) {
     //submit record to es and return
     // non blocking
     es.submit(()->{
        someSyncTask(record);
        latch.countDown();
        
    })
 }

 public boolean blockTillAllRecordsAreProcessed(CountDownLatch latch){
     System.out.println("waiting for processes to complete....");
     try {
          //current thread will get notified if all chidren's are done 
          // and thread will resume from wait() mode.
          latch.await();
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
       }

   }

Read more here: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html在此处阅读更多信息: https : //docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM