我们先来温习下如何让创建多线程:
“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<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吧😀。
首先定义一个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
”我写出这样干净的代码,老板直夸我
云南丽江旅游攻略
使用ThreadLocal怕内存泄漏?
Java进阶之路思维导图
程序员必看书籍推荐
3万字的Java后端面试总结(附PDF)
扫码二维码,获取更多精彩。或微信搜Lvshen_9,可后台回复获取资料
1.回复"java" 获取java电子书; 2.回复"python"获取python电子书; 3.回复"算法"获取算法电子书; 4.回复"大数据"获取大数据电子书; 5.回复"spring"获取SpringBoot的学习视频。 6.回复"面试"获取一线大厂面试资料 7.回复"进阶之路"获取Java进阶之路的思维导图 8.回复"手册"获取阿里巴巴Java开发手册(嵩山终极版) 9.回复"总结"获取Java后端面试经验总结PDF版 10.回复"Redis"获取Redis命令手册,和Redis专项面试习题(PDF) 11.回复"并发导图"获取Java并发编程思维导图(xmind终极版)另:点击【我的福利】有更多惊喜哦。