如何实现处理线程的返回值

张贤 2020年03月11日 103次浏览

如何给 run 方法传参

  • 构造函数传参
  • 成员变量传参
  • 回调函数传参

如何实现处理线程的返回值

循环等待法

让主线程循环等待,直到目标线程返回值为止。需要自己实现循环等待的逻辑,如果等待的变量比较多,代码就会显得臃肿。而且我们只能设置一个循环等待的间隔,比如循环判断值是否为空,如果不为空则继续等待 100 ms,如果在 100 ms 内有了值,我们无法更精确地去控制等待的时间。

public class CycleWait implements Runnable {
    private String value;

    @Override
    public void run() {
        try {
            //模拟子线程耗时操作
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        value = "we have data now";
    }

    public static void main(String[] args) {
        CycleWait cycleWait = new CycleWait();
        Thread t = new Thread(cycleWait);
        t.start();
        //判断 cycleWait.value 是否为空,如果为空,则循环等待100 ms,直到 cycleWait.value 不为空
        while (cycleWait.value == null) {
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("value: " + cycleWait.value);
    }
}

Thread.join()

使用 Thread 类的 join() 方法阻塞当前线程以等待子线程处理完毕。但是这种方法无法做到更精细的控制。这种方法比较简单,不展开讲解。

Callable

通过 Callable 接口实现。Callable 接口里面有 call() 方法,作用与 Runnable() 方法的作用类似,但不同的是:call() 有返回值,Callable 需要与 FutureTask 配合使用。
这种方法有两种实现:通过 FutureTask 获取或者线程池获取,下面分别介绍这两种方法:

  • 通过 FutureTask 获取:
    首先定义一个 Callable 实现类,重写 call() 方法,返回一个 String。
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        String value="test";
        System.out.println("Ready to work");
        //模拟子线程耗时操作
        Thread.currentThread().sleep(3000);
        System.out.println("work done");
        return value;
    }
}

然后把 MyCallable 类的对象传给 FutureTask,再把 FutureTask 类的对象传给 Thread。最后通过task.get() 方法就可以阻塞,直到 Callable 的 call() 方法返回值。

public class FutureTaskDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> task=new FutureTask<String>(new MyCallable());
        new Thread(task).run();
        System.out.println("task return: "+ task.get());
    }
}
  • 通过线程池获取返回值
    与上面类似,不同的是通过线程池创建一个 Future 类的对象,通过 future.get() 方法接受 Callable 的返回值(上面的 FutureTask 也是实现了 Future 接口的类)。
public class ThreadPoolDemo {
    public static void main(String[] args){
        ExecutorService service = Executors.newCachedThreadPool();
        //通过 Future 接受返回值
        Future<String> future = service.submit(new MyCallable());
        //调用 future.get(),会阻塞在这里,直到 Callable 返回了值
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }finally {
            //关闭线程池
            service.shutdown();
        }
    }
}