如何获取线程返回结果
前言:
我们知道 Thread.run()
返回值是 void
, 那么当我们通过多线程执行任务的时候,如果想获取线程的返回值, 应该怎么做呢?思路是什么?
1.思路
如果你看过《Thread.start()之后是如何调用 run()方法的呢?
》 这篇文章,会知道当线程启动之后,最终操作系统会回调 Thread.run()
方法。那么我们就可以在 Thread.run()
方法里面做文章。比如我们写了一个类实现了Runnable
接口,
public class GetThreadResult implements Runnable {
@Override
public void run() {
hello();
}
public String hello() {
return "Hello";
}
}
那我们是不是可以用一个全局变量res
来接收hello()
方法的返回值呢,如果要拿线程的返回值,只需要把res
返回即可。
代码如下:
public class GetThreadResult implements Runnable {
/**
* 线程结果返回值
*/
private String res;
@Override
public void run() {
res = hello();
}
public String hello() {
return "Hello";
}
public String get() {
return res;
}
}
这样我们就可以通过调用get()
方法来获取返回值。
2.获取线程调用返回值
上面只是一个简单的思路,还有很多细节待完善,这里简单列举三个:
- 结果返回值如何返回通用的类型?
- 这样写完全不通用,要在每一个类里面都定义返回值变量,定义
get()
方法,如果做到通用? - 当我们调用
get()
方法时,run()
方法还没执行到,或者还没执行完怎么办?
下面我们来着重看下如何解决这三个问题。
针对问题1:如何返回通用的类型,我们使用泛型就可以。
针对问题2:如何做到通用的写法呢?《代码之美》第17章有提到:“所有计算机科学领域中的问题都可以通过一个额外的中间层来解决”,所以我们也可以引入中间类来做到通用。
针对问题3:我们可以添加一个状态标记字段,在我们调用get()
方法时如果状态是未完成,则让该线程等待(等线程执行完了则唤起该线程);如果状态是已经完成,则直接返回结果即可。
改造后的代码如下:
public class GetThreadResult<T> implements Runnable {
/**
* 为了少写一个中间类,这里直接用了函数式接口
*/
private Supplier<T> supplier;
private State state;
public GetThreadResult(Supplier<T> supplier) {
this.supplier = supplier;
this.state = State.INIT;
}
/**
* 获取结果的线程
*/
private Thread getResultThread;
/**
* 线程结果返回值
*/
private T res;
@Override
public void run() {
res = supplier.get();
this.state = State.COMPLETED;
if (Objects.nonNull(this.getResultThread)) {
// unpark 获取结果线程
LockSupport.unpark(this.getResultThread);
}
}
public T get() {
// 如果状态是已完成,则直接返回结果
if (this.state == State.COMPLETED) {
return res;
}
this.getResultThread = Thread.currentThread();
// park 获取结果线程
LockSupport.park();
return res;
}
/**
* 状态
*/
enum State {
/**
* 初始化
*/
INIT,
/**
* 已完成
*/
COMPLETED;
}
}
写个程序来检验一下:
public static void main(String[] args) {
GetThreadResult<String> res = new GetThreadResult<>(() -> {
System.out.println("当前线程名称:" + Thread.currentThread().getName());
return "Hello,Thread";
});
Thread thread = new Thread(res, "test-get-result-thread");
thread.start();
String str = res.get();
System.out.println("得到线程返回结果:" + str);
}
输出结果:
当前线程名称:test-get-result-thread
得到线程返回结果:Hello,Thread
这样一来,简易版的获取线程返回结果的程序就写好了。
小结
本篇文章简单实现了获取线程的返回结果,虽然还有很多很多细节需要考虑,比如线程执行中出现了异常怎么处理、如果是线程池中应该怎么处理、如何在获取线程执行结果的时候设置超时等待时间等等,但是我们有了已经总体的方向,如果你有兴趣继续完善,只需要补充里面的细节就好了。你会废了嘛?
好了,这篇文章就到这里了,感谢大家的观看!欢迎大家关注我的公众号:贾哇技术指南
。