繁体   English   中英

将线程的结果返回到单独的线程

[英]Return result of thread to a separate thread

例如,如果我有线程A和线程B。线程A是我运行大多数应用程序的主线程,但是当我需要从MySQL或其他外部源获取的值时,我将创建一个新线程(线程B)。

将值从线程B返回到线程A以进行进一步处理而又不使线程A等待值可用的最佳方法是什么?

使用队列,A将定期轮询队列,B可以将值异步放入队列

您可以使用ScheduledThreadPoolExecutor将返回Future而您无需等待。

用法示例(来自Java Docs on Future

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,因此可以由执行程序执行。 例如,上面带有Submit的构造可以替换为:

 FutureTask<String> future =
       new FutureTask<String>(new Callable<String>() {
         public String call() {
           return searcher.search(target);
       }});
     executor.execute(future);

如果您只需要完成一项任务,则可以使用Future并让另一个线程在方便时轮询(非阻塞) isDone()方法。

如果该任务经常执行,或者您有许多任务要执行,那么使用ConcurrentLinkedQueue可能是一个更好的主意,它还提供了一种支持阻塞的变体,直到将结果作为LinkedBlockingQueue交付为止。 再次:只要方便就在列表上进行轮询即可解决问题。

如果您不想轮询,则可以使用回调功能。 例如,如果使用Swing GUI,则可以从SwingUtilities类使数据库线程调用invokeLater ,因此在下一次可能的时间在主Swing线程上完成请求的处理。

这基于EventQueue类,在某些其他情况下使用起来可能更方便。

如果您不想与执行者打交道,只需创建一个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
}

对于线程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();
}

将主线程组织为事件循环:

BlockingQueue<Runnable> eventQueue=
    new LinkedBlockingQueue<>();
for (;;) {
    Runnable nextEvent=eventQueue.take();
    nextEvent.run();
}

线程B:

Result r=fetchFromDB();
eventQueue.put(new ResultHandler(r));

ResultHandler是一个Runnable,它知道如何处理结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM