簡體   English   中英

Java 支持嵌入式多線程

[英]Java Supporting Embedded Multi-Threading

需要 Java 多線程方面的幫助

我有一個案例如下:

有很多記錄。 每條記錄大約有 250 個字段。 每個字段都需要根據預定義的規則進行驗證。

所以我定義了一個類 FieldInfo 來表示每個字段:

public class FieldInfo {
    private String name;
    private String value;
    private String error_code;
    private String error_message;

    // ignore getters and setters
} 

一個類 Record 來表示一條記錄:

public class Record {
    List<FieldInfo> fields;

    // omit getter and setter here
}

以及規則接口和類:

public interface BusinessRule {
    // validating one field needs some other fields' value in the same record. So the list of all fields for a certain record passed in as parameter 
    public FieldInfo validate(List<FieldInfo> fields);
}

public class FieldName_Rule implements BusinessRule {

    public FieldInfo validate(List<FieldInfo> fields) { 
    // will do 
    // 1. pickup those fields required for validating this target field, including this target field
    // 2. performs validation logics A, B, C... 

    // note: all rules only read data from a database, no update/insert operations. 
    }
}

用戶可以一次提交 5000 條或更多記錄進行處理。 性能要求很高。 我正在考慮為提交的多個線程,例如5000條記錄(意味着一個線程運行多個記錄),並且在每個線程中,在每個記錄上分叉另一個多個線程以運行規則。

但不幸的是,這種嵌入式多線程在我的情況下總是消亡。

以下是上述解決方案的一些關鍵部分:

public class BusinessRuleService {

    @Autowired
    private ValidationHandler handler;

    public String process(String xmlRequest) {
        List<Record> records = XmlConverter.unmarshall(xmlRequest).toList();
        ExecutorService es = Executors.newFixedThreadPool(100);
        List<CompletableFuture<Integer> futures = 
                records.stream().map(r->CompletableFuture.supplyAsync(()-> handler.invoke(r), es)).collect(Collectors.toList());
        List<Integer> result = future.stream().map(CompletableFuture::join).collect(Collectors.toList());
        System.out.println("total records %d processed.", result.size());
        es.shutdown();
        return XmlConverter.marshallObject(records);
    }
}

@Component
public class ValidationHandlerImpl implements ValidationHandler {

    @Autowired
    private List<BusinessRule> rules;

    @Override
    public int invoke(Record record) {

        ExecutorService es = Executors.newFixedThreadPool(250);
        List<CompletableFuture<FieldInfo> futures = 
                rules.stream().map(r->CompletableFuture.supplyAsync(()-> r.validate(record.getFields()), es)).collect(Collectors.toList());
        List<FieldInfo> result = future.stream().map(CompletableFuture::join).collect(Collectors.toList());
        System.out.println("total records %d processed.", result.size());
        es.shutdown();
        return 0;
    }
}

工作流程是:用戶以 xml 字符串格式提交記錄列表。 應用程序端點之一在 BusinessRuleService 對象中啟動流程方法。 該過程使用 CompletableFuture 來組合任務並將任務提交給一個 ExecutorService,該服務具有一個大小為 100 的線程池。 CompletableFuture 列表中的每個任務然后啟動 ValidationHandler 對象。 ValidationHandler 對象組成另一個 CompletableFuture 任務,並將任務提交給另一個池大小與規則列表大小相同的 ExecutorService。

上面的解決方案是否合適?

注意:我目前的解決方案是:對提交的記錄進行順序處理。 每條記錄並行處理 250 條規則。 使用這個方案,5000條記錄需要2個多小時。 這種糟糕的表現是企業不能接受的。

我對並發/多線程編程很陌生。 非常感謝各種幫助!

這是眾所周知的“單生產者-多消費者”模式。 經典的解決方案是創建一個BlockingQueue<Record> queue ,並按照讀取的速度將記錄放在那里。 在隊列的另一端,一些工作線程從queue讀取記錄並處理它們(在我們的例子中,驗證字段):

class ValidatingThread extends Tread {
   BlockingQueue<Record> queue;
   FieldName_Rule validator = new FieldName_Rule();

   public Validator (BlockingQueue<Record> queue) {
      this.queue = queue;
   }

   public void run() {
      Record record = queue.take();
      validator.validate(collectFields(record));
   }
}

最佳線程數等於Runtime.getRuntime().availableProcessors() 一開始就啟動它們,不要使用“嵌入式多線程”。 在處理完所有記錄后如何停止線程的任務留作學習任務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM