Can I use Callable threads without ExecutorService?

后端 未结 4 1847
花落未央
花落未央 2021-02-02 11:00

Can I use Callable threads without ExecutorService? We can use instances of Runnable and subclasses of Thread without ExecutorService and this code works normally. But this code

4条回答
  •  孤独总比滥情好
    2021-02-02 11:43

    The simple direct answer is that you need to use an ExecutorService if you want to use a Callable to create and run a background thread, and certainly if you want to obtain a Future object, or a collection of Futures. Without the Future, you would not be able to easily obtain the result returned from your Callable or easily catch Exceptions generated. Of course you could try to wrap your Callable in a Runnable, and then run that in a Thread, but that would beg the question of why, since by doing so you would lose much.


    Edit
    You ask in comment,

    Do you mean like the code below, which works?

    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();
                }
            }
        }
    }
    

    My reply: Yes. The code in the link "sort of" works. Yes, it creates background threads, but the results from the calculations performed in the Callables are being discarded, and all exceptions are being ignored. This is what I mean by "since by doing so you would lose much".


    e.g.,

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

    Edit 2
    Or if you want the results returned as they occur, use a CompletionService to wrap your ExecutorService, something I've never attempted before:

    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 {
          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 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!");
       }
    }
    

提交回复
热议问题