【问题标题】:How can a Thread return a value after finishing its job?线程完成工作后如何返回值?
【发布时间】:2010-06-29 13:36:27
【问题描述】:

假设我们有一个简单的例子:

public Example extends Thread{

    String temp;    

    public Example(){
    }

    @Override
    public void run(){
        .
        .
        .
        .
        temp = "a_value";
    }

    public static void main(String[] args) {

        Example th = new Example();
        th.start();
    }

}

线程完成工作后如何将字符串临时返回给我?

【问题讨论】:

  • 应该是th.start()。而且您确实实现了一种从线程返回值的方法。

标签: java multithreading


【解决方案1】:

使用(相对)新的 Callable<T> 而不是 Runnable(在 1.5 和更新版本中可用):

这是一个(简单的)示例:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class Main {

    public static void main(final String[] argv) {
        final ExecutorService service;
        final Future<String>  task;

        service = Executors.newFixedThreadPool(1);        
        task    = service.submit(new Foo());

        try {
            final String str;

            // waits the 10 seconds for the Callable.call to finish.
            str = task.get(); // this raises ExecutionException if thread dies
            System.out.println(str);
        } catch(final InterruptedException ex) {
            ex.printStackTrace();
        } catch(final ExecutionException ex) {
            ex.printStackTrace();
        }

        service.shutdownNow();
    }
}

class Foo implements Callable<String> {
    public String call() {
        try {
            // sleep for 10 seconds
            Thread.sleep(10 * 1000);
        } catch(final InterruptedException ex) {
            ex.printStackTrace();
        }

        return ("Hello, World!");
    }
}

【讨论】:

  • “(相对)新的” 相对于什么?它是在一个现已结束其使用寿命的版本中推出的。
  • 相对于版本... 1.6 是最新的,它是在 1.5 中发布的。将其与 1.0 中的 Thread 进行比较...学生从中学习的许多书籍中都没有 Callable。
  • foo 是 BigBang Theory 中“Baznga”的软件程序员版本 :)
  • @TofuBeer 你也可以帮忙给线程方法call()提供输入吗:-)
  • @Mohit 你不能,因为 API 不允许你 docs.oracle.com/javase/8/docs/api/java/util/concurrent/… 你可以做的是在 Foo 中创建成员变量并在构造函数中设置它们并稍后在调用方法。例如; task = service.submit(new Foo(1,"abc"));
【解决方案2】:

查看Future 接口javadoc。它有示例用法向您展示如何执行此操作。

【讨论】:

    【解决方案3】:

    您可以通过观察者模式来实现这一点。 在完成线程通知所有侦听器它已经完成并且他们可以检索值(通过getter)。或者它甚至可以发送计算值。

    或者您可以使用任务,请参阅FutureTask,这是一个可运行的(实际上如下所述的 Callable ),它返回结果并可以引发异常。

    【讨论】:

    • 我认为这是观察者模式的正确答案。如果您要阻止执行等待结果,那么拥有一个新线程有什么意义?
    【解决方案4】:

    如果您不想交换解决方案以使用 Callable 对象,那么您也可以使用队列并以这种方式从线程返回结果。
    我像这样重写了您的示例:

    import java.util.PriorityQueue;
    import java.util.Queue;
    
    public class GetResultFromThread {
        public static void main(String[] args) throws Exception {
            Queue<String> queue = new PriorityQueue<String>();
            int expectedResults = 2;
            for (int i = 0; i < expectedResults; i++) {
                new Example(queue).start();
            }
    
            int receivedResults = 0;
            while (receivedResults < expectedResults) {
                if (!queue.isEmpty()) {
                    System.out.println(queue.poll());
                    receivedResults++;
                }
                Thread.sleep(1000);
            }
        }
    }
    
    class Example extends Thread {
        private final Queue<String> results;
    
        public Example(Queue<String> results) {
            this.results = results;
        }
    
        @Override
        public void run() {
            results.add("result from thread");
        }
    }
    

    请注意,您应该考虑同步和并发!

    【讨论】:

    猜你喜欢
    • 2015-01-14
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-18
    相关资源
    最近更新 更多