25. CompletionService:非同期タスクをバッチで実行する方法は?-並行処理ツール

「ThreadPoolExecutor + Future」を利用した問い合わせ申請スキームは以下の通りです。

// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 异步向电商S1询价
Future<Integer> f1 = 
  executor.submit(
    ()->getPriceByS1());
// 异步向电商S2询价
Future<Integer> f2 = 
  executor.submit(
    ()->getPriceByS2());
// 异步向电商S3询价
Future<Integer> f3 = 
  executor.submit(
    ()->getPriceByS3());
    
// 获取电商S1报价并异步保存
executor.execute(
  ()->save(f1.get()));
  
// 获取电商S2报价并异步保存
executor.execute(
  ()->save(f2.get())
  
// 获取电商S3报价并异步保存  
executor.execute(
  ()->save(f3.get())

問題は、eコマースのS1見積もりを取得するのに長い時間がかかる場合、eコマースのS2見積もりが非常に短い場合でも、メインスレッドがf1.getでブロックされているため、S2の見積もりを保存する操作を最初に実行できないことです。 ()操作。

解決策:ブロッキングキューを追加し、S1、S2、S3の引用符をブロッキングキューに取得し、メインスレッドでブロッキングキューを使用して、最初に取得した引用符がデータベースに保存されるようにします。

// 创建阻塞队列
BlockingQueue<Integer> bq = new LinkedBlockingQueue<>();
//电商S1报价异步进入阻塞队列  
executor.execute(()->
  bq.put(f1.get()));
//电商S2报价异步进入阻塞队列  
executor.execute(()->
  bq.put(f2.get()));
//电商S3报价异步进入阻塞队列  
executor.execute(()->
  bq.put(f3.get()));
//异步保存所有报价  
for (int i=0; i<3; i++) {
  Integer r = bq.take();
  executor.execute(()->save(r));
}  

1. CompletionServiceを使用して照会システムを実現する

CompletionServiceの実装原則は、ブロッキングキューも内部で維持し、タスク実行結果のFutureオブジェクトをブロッキングキューに追加します。

1.1では、どのようにCompletionServiceを作成しますか?

CompletionServiceインターフェースの実装クラスは、ExecutorCompletionServiceという2つの構築メソッドです。

ExecutorCompletionService(Executor executor)ExecutorCompletionService(Executor executor, BlockingQueue<Future<V>> completionQueue)

次に、デフォルトで無制限のLinkedBlockingQueueを使用します。タスク実行結果のFutureオブジェクトがcompletionQueueに追加されます。
問い合わせを実装するコードは次のとおりです。

// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 创建CompletionService
CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);

// 异步向电商S1询价
cs.submit(()->getPriceByS1());
// 异步向电商S2询价
cs.submit(()->getPriceByS2());
// 异步向电商S3询价
cs.submit(()->getPriceByS3());

// 将询价结果异步保存到数据库
for (int i=0; i<3; i++) {
  Integer r = cs.take().get();
  executor.execute(()->save(r));
}

1.2 CompletionServiceインターフェースの説明

Future<V> submit(Callable<V> task);
// V result传入的结果引用
Future<V> submit(Runnable task, V result);

// 以下三个都跟阻塞队列有关
// 如果队列为空,调用 take() 方法的线程会被阻塞
Future<V> take() throws InterruptedException;
// 如果队列为空,调用 poll() 方法的线程返回null
Future<V> poll();
Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;

2. CompletionServiceを使用して、ダボでForking Clusterを実現します

ダボフォークのクラスタモデル並列通話サービスで複数のクエリをサポートするには、限り、成功したリターン結果があるとして、サービス全体を返すことができます

// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 创建CompletionService
CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
// 用于保存Future对象
List<Future<Integer>> futures = new ArrayList<>(3);
//提交异步任务,并保存future到futures 
futures.add(cs.submit(()->geocoderByS1()));
futures.add(cs.submit(()->geocoderByS2()));
futures.add(cs.submit(()->geocoderByS3()));
// 获取最快返回的任务执行结果
Integer r = 0;
try {
  // 只要有一个成功返回,则break
  for (int i = 0; i < 3; ++i) {
    r = cs.take().get();
    //简单地通过判空来检查是否成功返回
    if (r != null) {
      break;
    }
  }
} finally {
  //取消所有任务
  for(Future<Integer> f : futures)
    f.cancel(true);
}
// 返回结果
return r;

最初に、スレッドプールエグゼキューター、CompletionServiceオブジェクトcs、およびFutureタイプリストfuturesを作成します。CompleteServiceのsubmit()メソッドを呼び出して非同期タスクが送信されるたびに、Futureオブジェクトが返されます。先物。cs.take()。Get()を呼び出すことで、タスクの最速の実行結果を取得できます。正しく返された結果が得られれば、すべてのタスクをキャンセルして最終結果を返すことができます。

97件の元の記事を公開 賞賛3 10,000+ビュー

おすすめ

転載: blog.csdn.net/qq_39530821/article/details/102762675