【问题标题】:Return result of thread to a separate thread将线程的结果返回到单独的线程
【发布时间】:2014-02-19 09:38:04
【问题描述】:

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

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

【问题讨论】:

标签: java multithreading


【解决方案1】:

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

如果该任务被频繁执行或者您有许多任务要执行,使用ConcurrentLinkedQueue 可能是一个更好的主意,它还有一个支持阻塞的变体,直到结果以LinkedBlockingQueue 传递。再次重申:只要方便,就可以在列表中进行轮询。

如果您不想进行轮询,则可以使用回调功能。例如,如果您使用 Swing GUI,您可以让 DB 线程从 SwingUtilities 类调用 invokeLater,因此在下一个可能的时间在主 Swing 线程上处理请求。

这是基于EventQueue 类,在某些其他场景中使用可能更方便。

【讨论】:

    【解决方案2】:

    使用队列,A会定期轮询队列,B可以异步把值放到队列中

    【讨论】:

    • 对不起,我已经编辑了帖子以使其更清晰,但我希望线程 A 继续正常执行,直到有响应。
    • 可以继续执行。但它仍然需要每隔一段时间轮询一次,以便在响应准备好时执行某些操作。
    【解决方案3】:

    您可以使用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);
    

    【讨论】:

    • 为什么你建议构造一个FutureTask并传递给Executor,而ExecutorService有一个submit方法,为你构造Future?
    • 好吧,这不是 OP 想要的,因为主线程无论如何都会等待future.get()...
    【解决方案4】:

    对于线程 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 想要的
    • @Adam Dyga:谢谢。但是,您能否再次查看答案?主线程将在它真正需要该值时等待。本质上,OP 应该在该线程的输出是必需之前调用thread.join()。在那之前,主线程正常继续,无需等待任何东西。我写了myFunc作为例子(这个函数的内容可以放在主线程的任何地方)。
    【解决方案5】:

    如果您不想处理执行者,只需创建一个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 想要的
    • Future 有 isDone() 方法在需要时进行轮询。我不明白你的担忧。
    【解决方案6】:

    将你的主线程组织成一个事件循环:

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

    线程 B:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-23
      • 2020-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多