我可以在没有执行器服务的情况下使用可调用线程吗?

我可以在没有执行器服务的情况下使用可调用线程吗?我们可以在没有 ExecutorService 的情况下使用 Runnable 的实例和 Thread 的子类,并且此代码可以正常工作。但此代码的工作方式始终如一:

public class Application2 {

    public static class WordLengthCallable implements Callable {
        public static int count = 0;
        private final int numberOfThread = count++;

        public Integer call() throws InterruptedException {
            int sum = 0;
            for (int i = 0; i < 100000; i++) {
               sum += i;
            }
            System.out.println(numberOfThread);
            return numberOfThread;
       }
   }
   public static void main(String[] args) throws InterruptedException {
       WordLengthCallable wordLengthCallable1 = new WordLengthCallable();
       WordLengthCallable wordLengthCallable2 = new WordLengthCallable();
       WordLengthCallable wordLengthCallable3 = new WordLengthCallable();
       WordLengthCallable wordLengthCallable4 = new WordLengthCallable();
       wordLengthCallable1.call();
       wordLengthCallable2.call();
       wordLengthCallable3.call();
       wordLengthCallable4.call();
       try {
           Thread.sleep(1000);
       } catch (InterruptedException e) {
          e.printStackTrace();
      }
      System.exit(0);
  }
}

使用 ExecutorService,代码只需几个线程即可工作。我的错误在哪里?


答案 1

虽然 s 通常是使用预期的用例创建的,但它们从不限于以这种方式使用。interface

给定 一个,你可以将它提交给 一个,或者把它传递给构造函数,或者你可以直接调用它的方法,就像你可以调用任何方法而不涉及多线程一样。还有更多的用例,例如AWT,所以永远不要指望列表是完整的。RunnableExecutorServiceThreadrun()interfaceEventQueue.invokeLater(Runnable)

给定 一个 ,你有相同的选项,所以重要的是要强调,与你的问题所暗示的不同,直接调用不涉及任何多线程。它只是像任何其他普通方法调用一样执行该方法。Callablecall()

由于没有构造函数使用 a 和 没有 a,因此需要稍微多一些代码:Thread(Callable)CallableThreadExecutorService

FutureTask<ResultType> futureTask = new FutureTask<>(callable);
Thread t=new Thread(futureTask);
t.start();
// …
ResultType result = futureTask.get(); // will wait for the async completion

答案 2

简单的直接答案是,如果你想使用一个 Callable 来创建和运行后台线程,当然,如果你想获得一个 Future 对象或 Future 的集合,你需要使用 ExecutorService。如果没有 Future,您将无法轻松获取从 Callable 返回的结果,也无法轻松捕获生成的异常。当然,你可以尝试将你的 Callable 包装在 Runnable 中,然后在 Thread 中运行它,但这会引出一个问题,因为这样做会给你带来很多损失。


编辑
您在评论中询问,

你的意思是像下面的代码一样,它的工作原理?

public class Application2 {
    public static class WordLengthCallable implements Callable {
    public static int count = 0;
    private final int numberOfThread = count++;

    public Integer call() throws InterruptedException {
        int sum = 0;
        for (int i = 0; i < 100000; i++) {
            sum += i;
        }
        System.out.println(numberOfThread);
        return numberOfThread;
    }
}
    public static void main(String[] args) throws InterruptedException {
        new Thread(new MyRunnable()).start();
        new Thread(new MyRunnable()).start();
        new Thread(new MyRunnable()).start();
        new Thread(new MyRunnable()).start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.exit(0);
    }

    public static class MyRunnable implements Runnable {

        @Override
        public void run() {
            try {
                new WordLengthCallable().call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

我的回答是:是的。链接“排序”中的代码有效。是的,它会创建后台线程,但将丢弃在可调用文件中执行的计算结果,并忽略所有异常。这就是我所说的“因为这样做你会失去很多”。


例如,

  ExecutorService execService = Executors.newFixedThreadPool(THREAD_COUNT);
  List<Future<Integer>> futures = new ArrayList<>();
  for (int i = 0; i < THREAD_COUNT; i++) {
     futures.add(execService.submit(new WordLengthCallable()));
  }
  for (Future<Integer> future : futures) {
     try {
        System.out.println("Future result: " + future.get());
     } catch (ExecutionException e) {
        e.printStackTrace();
     }
  }

  Thread.sleep(1000);
  System.out.println("done!");
  execService.shutdown();

编辑 2
或者,如果您希望在结果发生时返回结果,请使用 CompletionService 来包装您的 ExecutorService,这是我以前从未尝试过的:

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletionServiceExample {
   public static class WordLengthCallable implements Callable<Integer> {
      private Random random = new Random();

      public Integer call() throws InterruptedException {
         int sleepTime = (2 + random.nextInt(16)) * 500;
         Thread.sleep(sleepTime);
         return sleepTime;
      }
   }

   private static final int THREAD_COUNT = 4;

   public static void main(String[] args) throws InterruptedException {
      ExecutorService execService = Executors.newFixedThreadPool(THREAD_COUNT);
      CompletionService<Integer> completionService = new ExecutorCompletionService<>(
            execService);

      for (int i = 0; i < THREAD_COUNT; i++) {
         completionService.submit(new WordLengthCallable());
      }
      execService.shutdown();

      try {
         while (!execService.isTerminated()) {
            int result = completionService.take().get().intValue();
            System.out.println("Result is: " + result);
         }
      } catch (ExecutionException e) {
         e.printStackTrace();
      }

      Thread.sleep(1000);
      System.out.println("done!");
   }
}

推荐