Java 我可以在没有 ExecutorService 的情况下使用 Callable 线程吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25231149/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I use Callable threads without ExecutorService?
提问by user3233853
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 works consistently:
我可以在没有 ExecutorService 的情况下使用 Callable 线程吗?我们可以在没有 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);
}
}
With ExecutorService the code works with few threads. Where are my mistakes?
使用 ExecutorService 代码可以使用很少的线程。我的错误在哪里?
回答by Hovercraft Full Of Eels
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.
简单直接的答案是,如果您想使用 Callable 来创建和运行后台线程,则需要使用 ExecutorService,当然如果您想获取 Future 对象或 Futures 的集合。如果没有 Future,您将无法轻松获取从 Callable 返回的结果或轻松捕获生成的异常。当然,您可以尝试将 Callable 包装在 Runnable 中,然后在 Thread 中运行它,但这会引出为什么会这样的问题,因为这样做会损失很多。
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".
我的回答:是的。链接“有点”中的代码有效。是的,它创建了后台线程,但是 Callables 中执行的计算结果被丢弃,所有异常都被忽略。这就是我所说的“因为这样做你会失去很多”。
e.g.,
例如,
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();
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:
编辑 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!");
}
}
回答by eckes
Yes you can use the call()
method of a Callable or the run()
method of a Runnable from your own thread directly. However this should be your last resort in special circumstances (for example integrating legacy code or unit tests). Scanners might detect this and alert you about a possible architectural problem, so it is better to not do it.
是的,您可以直接从您自己的线程使用call()
Callable 的run()
方法或Runnable的方法。但是,这应该是您在特殊情况下的最后手段(例如集成遗留代码或单元测试)。扫描器可能会检测到这一点并提醒您可能存在架构问题,因此最好不要这样做。
You could also use your own ExecutorService
(or use Guava's MoreExecutors.sameThreadExecutor()
) which does basically the calling in the invoking thread. This will isolate your "unclean" usage of the interface to this Executor and allow it to use a different Executor whenever you want.
您也可以使用自己的ExecutorService
(或使用 Guava 的MoreExecutors.sameThreadExecutor()
),它基本上在调用线程中进行调用。这会将您对该 Executor 接口的“不干净”使用隔离开来,并允许它随时使用不同的 Executor。
BTW: be careful, when you inherit from Thread
, you should never use it without start/stop as that might lead to a leak. This is one of the reasons why bug scanners alert on calling run() methods directly.
顺便说一句:小心,当你从 继承时Thread
,你不应该在没有启动/停止的情况下使用它,因为这可能会导致泄漏。这是错误扫描器在直接调用 run() 方法时发出警报的原因之一。
回答by Holger
While interface
s are often created with an intended use case, they are never restricted to be used in that way.
虽然interface
s 通常是根据预期用例创建的,但它们从不限于以这种方式使用。
Given a Runnable
you can submit it to an ExecutorService
, or pass it to the constructor of Thread
or you can invoke its run()
method directly like you can invoke any interface
method without multi-threading involved. And there are more use cases, e.g. AWT EventQueue.invokeLater(Runnable)
so never expect the list to be complete.
给定 a ,Runnable
您可以将其提交给 an ExecutorService
,或将其传递给 的构造函数,Thread
或者您可以run()
直接调用其方法,就像您可以调用任何interface
不涉及多线程的方法一样。还有更多的用例,例如 AWT,EventQueue.invokeLater(Runnable)
所以永远不要期望列表是完整的。
Given a Callable
, you have the same options, so it's important to emphasize that, unlike your question suggests, invoking call()
directly does not involve any multi-threading. It just executes the method like any other ordinary method invocation.
给定 a Callable
,您有相同的选项,因此重要的是要强调的是,与您的问题所暗示的不同,call()
直接调用不涉及任何多线程。它只是像任何其他普通方法调用一样执行方法。
Since there is no constructor Thread(Callable)
using a Callable
with a Thread
without an ExecutorService
requires slightly more code:
由于没有Thread(Callable)
使用Callable
带 aThread
不带 an 的构造函数ExecutorService
需要更多的代码:
FutureTask<ResultType> futureTask = new FutureTask<>(callable);
Thread t=new Thread(futureTask);
t.start();
// …
ResultType result = futureTask.get(); // will wait for the async completion
回答by Prashant K S
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
*/