从Thread返回值

Nee*_*eta 86 java multithreading android

我有一个方法HandlerThread.一个值在内部发生变化Thread,我想将它返回给test()方法.有没有办法做到这一点?

public void test()
{   
    Thread uiThread = new HandlerThread("UIHandler"){
        public synchronized void run(){
            int value; 
            value = 2; //To be returned to test()
        }
    };
    uiThread.start();
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*erg 72

通常你会这样做

 public class Foo implements Runnable {
     private volatile int value;

     @Override
     public void run() {
        value = 2;
     }

     public int getValue() {
         return value;
     }
 }
Run Code Online (Sandbox Code Playgroud)

然后你可以创建线程并检索值(假设已经设置了值)

Foo foo = new Foo();
Thread thread = new Thread(foo);
thread.start();
thread.join();
int value = foo.getValue();
Run Code Online (Sandbox Code Playgroud)

tl;dr线程无法返回值(至少没有回调机制).您应该像普通类一样引用一个线程并询问该值.

  • @HamzahMalik为了确保线程完成使用`Thread t = new Thread(foo); t.start(); t.join(); foo.getValue();`.`t.join()`阻塞直到线程结束. (10认同)
  • 嗯,但如果线程没有完成怎么办? (3认同)
  • 这真的有用吗?我得到`方法getValue()未定义为Thread`类型. (2认同)
  • @pmichna,很好的发现。从“t.getValue()”更改为“foo.getValue()”。 (2认同)
  • 是! 做得好!“易失” ftw!与接受的答案不同,这是正确的! (2认同)
  • @HariKiran 是的,正确,每个线程返回一个独立的值。 (2认同)

Ada*_*man 69

您可以使用本地最终变量数组.变量必须是非基本类型,因此您可以使用数组.您还需要同步两个线程,例如使用CountDownLatch:

public void test()
{   
    final CountDownLatch latch = new CountDownLatch(1);
    final int[] value = new int[1];
    Thread uiThread = new HandlerThread("UIHandler"){
        @Override
        public void run(){
            value[0] = 2;
            latch.countDown(); // Release await() in the test thread.
        }
    };
    uiThread.start();
    latch.await(); // Wait for countDown() in the UI thread. Or could uiThread.join();
    // value[0] holds 2 at this point.
}
Run Code Online (Sandbox Code Playgroud)

你也可以使用Executor和之Callable类的:

public void test() throws InterruptedException, ExecutionException
{   
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Callable<Integer> callable = new Callable<Integer>() {
        @Override
        public Integer call() {
            return 2;
        }
    };
    Future<Integer> future = executor.submit(callable);
    // future.get() returns 2 or raises an exception if the thread dies, so safer
    executor.shutdown();
}
Run Code Online (Sandbox Code Playgroud)

  • 由于CountDownLatch的内存一致性保证,我们实际上不需要显式同步访问值.值数组创建发生在uiThread启动(程序顺序规则)之前,它与2的赋值[0]同步 - [thread start](http://docs.oracle.com/javase/specs/jls/se7 /html/jls-17.html#jls-17.4.4))发生在latch.countDown()(程序顺序规则)之前 - 发生在latch.await()(保证来自CountDownLatch)之前 - 在读取之前发生来自值[0](程序订单规则). (4认同)
  • 不.此代码不正确.未正确同步对值的访问. (3认同)

Det*_*roc 27

您正在寻找的可能是Callable<V>接口代替Runnable,并使用Future<V>对象检索值,这也让您等到计算出值.你可以通过一个ExecutorService你可以得到的来实现这一目标Executors.newSingleThreadExecutor().

public void test() {
    int x;
    ExecutorService es = Executors.newSingleThreadExecutor();
    Future<Integer> result = es.submit(new Callable<Integer>() {
        public Integer call() throws Exception {
            // the other thread
            return 2;
        }
    });
    try {
        x = result.get();
    } catch (Exception e) {
        // failed
    }
    es.shutdown();
}
Run Code Online (Sandbox Code Playgroud)


Ele*_*fee 6

这个解决方案怎么样?

它不使用Thread类,但它是并发的,并且在某种程度上它完全符合您的要求

ExecutorService pool = Executors.newFixedThreadPool(2); // creates a pool of threads for the Future to draw from

Future<Integer> value = pool.submit(new Callable<Integer>() {
    @Override
    public Integer call() {return 2;}
});
Run Code Online (Sandbox Code Playgroud)

现在你所要做的就是value.get()在你需要获取返回的值时说,线程会在你给出value一个值的第二个时间启动,所以你不必再说threadName.start()了.

Future是对该计划的承诺,您向计划保证,您将在不久的将来获得它所需的价值

如果你.get()在它完成之前调用它,那么调用它的线程将只是等到它完成


Tom*_*ine 5

如果你想要调用方法的值,那么它应该等待线程完成,这使得使用线程有点毫无意义。

为了直接回答您的问题,该值可以存储在调用方法和线程都有引用的任何可变对象中。您可以使用 external this,但除了用于琐碎的示例外,这不会特别有用。

关于问题中的代码的一点说明:扩展Thread通常是糟糕的风格。事实上,不必要地扩展类是一个坏主意。我注意到您的run方法由于某种原因是同步的。现在,在这种情况下,对象是Thread您可能会干扰Thread使用其锁定的任何对象(在参考实现中,与joinIIRC 有关)。

  • 这通常毫无意义,但在 Android 中,您无法向主线程上的服务器发出网络请求(以保持应用程序响应),因此您必须使用网络线程。在某些情况下,您需要在应用程序恢复之前获得结果。 (4认同)

Vin*_*nto 5

从 Java 8 开始,我们有CompletableFuture. 在您的情况下,您可以使用该方法supplyAsync在执行后获取结果。

在这里找到一些参考。

    CompletableFuture<Integer> completableFuture
      = CompletableFuture.supplyAsync(() -> yourMethod());

   completableFuture.get() //gives you the value
Run Code Online (Sandbox Code Playgroud)