
点击上方蓝字关注我!
Callable实现线程通信
我们先来温习下如何让创建多线程:
“
1.继承
Thread
2.实现
Runnable
3.调用
Callable
4.使用线程池
ThreadPoolExecutor
”
我们在平时的开发中肯定遇到过【B线程如何获取A线程中的数据】,经验老道的程序员首先会想到使用Callable
实现。直接看代码:
如上图,线程A【Thread-0
】里面存入了字符串【Lvshen的技术小屋
】。我们要在主线程【main
】获取这个值,就采用如上方法。测试结果如下:
10:51:12.756 [Thread-0] INFO com.lvshen.demo.thread.future.Test - 当前线程:Thread-0
当前线程:[main],取出的值:[Lvshen的技术小屋]
FutureTask
细心的你肯定看到了这段代码
FutureTask<String> myFutureTask = new FutureTask<>(callable);
数据是从FutureTask
里面取出的,那么FutureTask
是个什么东东?
FutureTask
类是Future
的实现,它同时也实现了Runnable
,因此也可以被Executor
执行。
继承树如下:
那么FutureTask
有什么特点呢?
-
一个可取消的异步任务 -
该类提供了 Future
的基本实现,提供了启动和取消计算、查询计算是否完成以及检索计算结果的方法 -
只有在计算完成后才可检索结果;如果计算尚未完成, get
方法将阻塞 -
计算完成以后,计算不能重启或取消(除非调用 runAndReset
方法)
一个FutureTask
可以用来包装一个Callable
或Runnable
对象。因为FutureTask
实现了Runnable
接口,一个FutureTask
可以被提交给一个Executor
来执行。
这里我们简单看下get()
方法为什么能获取到其他线程的值。
首先创建FutureTask
,设置状态为NEW。
get()
为阻塞获取。
awaitDone()
为线程阻塞的方法,再来看看report()
方法:
其中
outcome
就是我们要获取的值。outcome
值来源于set()
方法。
当线程start
时,会调用FutureTask
的run()
方法,这里注意两个地方:
“
1.
result
的值为call()
方法的返回值2.
result
会存进set()
方法中”
手写FutureTask
我们大概了解了FutureTask
的结构,不如我们来手写一个FutureTask
吧😀。
首先定义一个MyFutureTask
类并实现Runnable
接口
public class MyFutureTask<T> implements Runnable {
...
}
然后定义几个属性
Callable<T> callable;
T result;
volatile String state = "NEW";
LinkedBlockingQueue<Thread> queue = new LinkedBlockingQueue<Thread>();
需要一个callable
对象,用来接收外面传进来的callable
;result
接收call()
方法返回的值;”NEW”为初始状态,用作标记;queue
为阻塞队列,用于存放当前线程。
定义构造函数:
public MyFutureTask(Callable<T> callable) {
this.callable = callable;
}
定义get()
方法:
public T get() {
if ("END".equals(state)) {
return result;
}
while (!"END".equals(state)) {
queue.add(Thread.currentThread());
LockSupport.park();
}
return result;
}
队列中添加一次线程,阻塞一次当前线程。
@Override
public void run() {
try {
result = callable.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
state = "END";
}
Thread th = queue.poll();
if (queue != null) {
LockSupport.unpark(th);
th = queue.poll();
}
}
启动线程时会调用run()
方法,callable.call()
获取线程中存入的值并赋值给result
,从队列中取出线程,如果有值,解锁当前线程,然后继续取值。
我么来测试一下:
测试结果:
效果已经达到。如果需要源码可以到我的github下载
“
https://github.com/lvshen9/demo/blob/lvshen-dev/src/main/java/com/lvshen/demo/thread/future
”
往期推荐


扫码二维码
获取更多精彩
Lvshen_9


原文始发于微信公众号(Lvshen的技术小屋):实现多线程间通信的FutureTask,我们来手写一个
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/262609.html