我可以在没有ExecutorService的情况下使用Callable线程吗?

use*_*853 15 java concurrency multithreading executorservice java.util.concurrent

我可以在没有ExecutorService的情况下使用Callable线程吗?我们可以使用Runnable的实例和没有ExecutorService的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);
  }
}
Run Code Online (Sandbox Code Playgroud)

使用ExecutorService,代码可以使用少量线程.我的错误在哪里?

Hol*_*ger 32

虽然interfaces通常是用预期的用例创建的,但它们绝不限于以这种方式使用.

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

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

由于没有构造函数Thread(Callable)使用Callablea Thread而不ExecutorService需要更多代码:

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


Hov*_*els 6

简单的直接答案是,如果要使用Callable创建和运行后台线程,则需要使用ExecutorService,当然,如果要获取Future对象或Futures集合,则需要使用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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的回答:是的.链接"排序"中的代码有效.是的,它会创建后台线程,但会丢弃Callables中执行的计算结果,并忽略所有异常.这就是我所说的"因为这样做会让你失去很多".


例如,

  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();
Run Code Online (Sandbox Code Playgroud)

编辑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!");
   }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class MainClass {
    public static void main(String[] args) {
        try {
            Callable<String> c = () -> {
                System.out.println(Thread.currentThread().getName());
                return "true";
            };
            FutureTask<String> ft = new FutureTask<String>(c);
            Thread t = new Thread(ft);
            t.start();

            String result = ft.get();
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/*
   Output: 
   Thread-0 
   true
 */
Run Code Online (Sandbox Code Playgroud)