簡體   English   中英

適用於“主”線程的Java執行器

[英]Java Executor for “main” thread

我想從程序的“主”線程(類似於Android中的主循環程序)創建一個Executor ,然后運行直到它處理了提交給它的所有內容:

public class MyApp {
  private static Callable<Integer> task = () -> {
    // ... return an int somehow ...
  };

  public static void main(String[] args) throws ExecutionException, InterruptedException {
    ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
    Thread main = Thread.currentThread();
    ExecutorService executorService = Executors.newSingleThreadExecutor(r -> main);

    service.submit(task).addListener(() -> {
      /// ... do something with the result ...
    }, executorService);

    executorService.awaitTermination(100, TimeUnit.SECONDS);
  }
}

但是我得到了一個IllegalThreadState異常:

SEVERE: RuntimeException while executing runnable MyApp$$Lambda$20/0x00000008000a6440@71f06a3c with executor java.util.concurrent.Executors$FinalizableDelegatedExecutorService@47add263
java.lang.IllegalThreadStateException
    at java.base/java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:926)
    at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1343)
    at java.base/java.util.concurrent.Executors$DelegatedExecutorService.execute(Executors.java:687)
    at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1137)
    at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:957)
    at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:726)
    at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.afterRanInterruptibly(TrustedListenableFutureTask.java:131)
    at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:133)
    at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:78)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)

我可以在新線程上啟動ExecutorService ,然后等待它,但這似乎很浪費。

有沒有什么好方法可以從當前線程創建Executor ,並等待它處理已提交給它的所有內容?

您可能正在尋找類似CompletionService東西:您向此任務提交任務,並且它按完成順序將其返回。

ExecutorService service = Executors.newFixedThreadPool(1);
ExecutorCompletionService<Integer> comp = new ExecutorCompletionService<>(service);

comp.submit(task);
// ... I assume you want to submit N tasks.

for (int i = 0; i < N; ++i) {
  Future<Integer> future = comp.take();
  Integer result = future.get();

  // ... do something with the result ...
}

項目完成后,將立即對其進行處理。 如果您能夠等到擁有所有東西之后再進行一次處理,則可以使用Guava的Futures.allAsList

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
List<Callable<Integer>> tasks = ...;

List<ListenableFuture<Integer>> futures = new ArrayList<>();
for (Callable<Integer> task : tasks) {
  futures.add(service.submit(task));
}

ListenableFuture<List<Integer>> resultsFuture = Futures.allAsList(futures);
List<Integer> results = resultsFuture.get();

// Process the results.

使用番石榴的MoreExecutors.newDirectExecutorService()

這將確保提交的代碼將在ThreadPool的同一線程中執行。 我知道,它不是主線程,但至少您不會像想要的那樣僅為偵聽器創建其他新線程。

import com.google.common.util.concurrent.*;
import org.junit.jupiter.api.Test;
import java.util.concurrent.*;

class ExecutorTest {
  private static Callable<Integer> task = () -> {
    System.out.println("in call: " + Thread.currentThread().getName());
    TimeUnit.SECONDS.sleep(1);
    return 0;
  };
  @Test
  void test() throws InterruptedException {
    ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
    ExecutorService executor = MoreExecutors.newDirectExecutorService();
    service.submit(task).addListener(() -> {
      System.out.println("in listener: " + Thread.currentThread().getName());
    }, executor);
    executor.awaitTermination(2, TimeUnit.SECONDS);
  }
}

這里記錄的方法invokeAll()等待所有任務完成
你可以這樣做

executorService.invokeAll();

請按照此帖子獲取更多說明

您正在嘗試在主線程中執行回調。 直接的方法是調用get()

YourResult result = service.submit(task).get();
/* Do something with your result... */

如果要異步執行回調,則可能對CompletionStage感興趣

CompletableFuture.runAsync(task).thenAccept(r -> /* do something with result */);

暫無
暫無

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

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