【发布时间】:2014-02-19 09:38:04
【问题描述】:
例如,如果我有线程 A 和线程 B。线程 A 是我运行大部分应用程序的主线程,但是当我需要从 MySQL 或其他外部源获取值时,我会创建一个新线程(线程 B)。
将值从线程 B 返回到线程 A 以进行进一步处理而不导致线程 A 等待值可用的最佳方法是什么?
【问题讨论】:
标签: java multithreading
例如,如果我有线程 A 和线程 B。线程 A 是我运行大部分应用程序的主线程,但是当我需要从 MySQL 或其他外部源获取值时,我会创建一个新线程(线程 B)。
将值从线程 B 返回到线程 A 以进行进一步处理而不导致线程 A 等待值可用的最佳方法是什么?
【问题讨论】:
标签: java multithreading
如果您有一个任务需要完成,您可以使用Future 并让其他线程在方便时轮询(非阻塞)isDone() 方法。
如果该任务被频繁执行或者您有许多任务要执行,使用ConcurrentLinkedQueue 可能是一个更好的主意,它还有一个支持阻塞的变体,直到结果以LinkedBlockingQueue 传递。再次重申:只要方便,就可以在列表中进行轮询。
如果您不想进行轮询,则可以使用回调功能。例如,如果您使用 Swing GUI,您可以让 DB 线程从 SwingUtilities 类调用 invokeLater,因此在下一个可能的时间在主 Swing 线程上处理请求。
这是基于EventQueue 类,在某些其他场景中使用可能更方便。
【讨论】:
使用队列,A会定期轮询队列,B可以异步把值放到队列中
【讨论】:
您可以使用ScheduledThreadPoolExecutor,它将返回Future,您无需等待。
示例用法(来自 Future 上的 java 文档)
interface ArchiveSearcher { String search(String target); }
class App {
ExecutorService executor = ...
ArchiveSearcher searcher = ...
void showSearch(final String target)
throws InterruptedException {
Future<String> future
= executor.submit(new Callable<String>() {
public String call() {
return searcher.search(target);
}});
displayOtherThings(); // do other things while searching
try {
displayText(future.get()); // use future
} catch (ExecutionException ex) { cleanup(); return; }
}
}
Future 任务也可以实现这一点(访问上面的链接,示例仅来自那里)
FutureTask 类是 Future 的实现,它实现了 Runnable,因此可以由 Executor 执行。例如,上面带有 submit 的构造可以替换为:
FutureTask<String> future =
new FutureTask<String>(new Callable<String>() {
public String call() {
return searcher.search(target);
}});
executor.execute(future);
【讨论】:
future.get()...
对于线程 B,声明一个实现 Runnable 的类。例如:
public class MyClass implements Runnable
{
private String input = null;
private String output = null;
public MyClass(String input)
{
this.input = input;
}
public String getOutput()
{
return output;
}
public void run()
{
output = func(input);
}
}
在线程 A(这是您的主线程)中,启动线程 B,并等待它仅在您真正需要其输出的地方完成。例如:
public String myFunc(String input) throws Exception
{
MyClass object = new MyClass(input);
Thread thread = new Thread(object);
thread.start();
// Do whatever you wanna do...
// ...
// ...
// And when you need the thread's output:
thread.join();
return object.getOutput();
}
【讨论】:
thread.join(),这不是 OP 想要的
thread.join()。在那之前,主线程正常继续,无需等待任何东西。我写了myFunc作为例子(这个函数的内容可以放在主线程的任何地方)。
如果您不想处理执行者,只需创建一个FutureTask 并将其传递给新线程即可。
FutureTask<String> f = new FutureTask<String>(new Callable<String>() {
@Override
public String call() {
return "";
}
});
new Thread(f).start();
while (Thread.currentThread().isInterrupted()) {
if (f.isDone()) {
System.out.println(f.get());
break;
}
//do smth else
}
【讨论】:
f.get(),这不是 OP 想要的
将你的主线程组织成一个事件循环:
BlockingQueue<Runnable> eventQueue=
new LinkedBlockingQueue<>();
for (;;) {
Runnable nextEvent=eventQueue.take();
nextEvent.run();
}
线程 B:
Result r=fetchFromDB();
eventQueue.put(new ResultHandler(r));
其中 ResultHandler 是一个 Runnable,它知道如何处理结果。
【讨论】: