前言
常用创建线程方式有Thread,Runable还有就是Callable,前面两者执行完之后无法返回结果,Callable提供执行线程完毕之后,可以获取结果机制,需要Future一起使用。今天以一个简单的案例来模拟实现机制。
场景描述
在一个阳光明媚的周末,一觉醒来以然是中午了,做饭时万万不可能的,所以需要订外卖咯,但是此时短信提醒又有快递需要去取,所以就出现了以下的常规操作,先定外卖,再去快递,取完快递回来接受外卖,最后享受午餐。
通过Callable实现
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
log.info("lk在" + DateUtil.timeFormat(new Date()) + "时间下单成功!预约发货时间为:2019-06-02 13:00:00");
try {
//模拟制作过程
Thread.sleep(5000);
log.info("制作完成,准备发货...");
} catch (InterruptedException e) {
log.error("制作出错!",e);
}
return "{订餐名称='全家桶', 到达时间=2019-06-02 13:00:00}";
}
};
FutureTask<String> task = new FutureTask<>(callable);
Thread thread = new Thread(task);
thread.start();
log.info("先去取快递...");
log.info("回来了,饭也到了,"+ task.get());
}
模拟底层实现机制完成场景
Person就是我,需要订单和取快递的那个
@Slf4j
public class Person {
public static void main(String[] args) {
Order order = ProductFactory.instance().createProduce("全家桶","lk",
DateUtil.formatTime("2019-06-02 13:00:00"));
log.info("先去取快递...");
log.info("回来了,饭也到了,"+ order.getProduct());
}
}
外卖制作者
@Slf4j
public class Product {
/**
* 用户名
*/
private String userName;
/**
* 外卖名称
*/
private String name;
/**
* 下单时间
*/
private Date orderTime;
/**
* 送达时间
*/
private Date deliveryTime;
public Product(String name, String userName, Date deliveryTime,Date orderTime) {
this.orderTime = orderTime;
this.name = name;
this.userName = userName;
this.deliveryTime = deliveryTime;
try {
//模拟制作过程
Thread.sleep(5000);
log.info(name + "制作完成,准备发货...");
} catch (InterruptedException e) {
log.error("制作出错!",e);
}
}
@Override
public String toString() {
return "{" +
"订餐名称='" + name + '\'' +
", 到达时间=" + DateUtil.timeFormat(deliveryTime) +
'}';
}
}
商家
@Slf4j
public class ProductFactory {
private static volatile ProductFactory factory;
public Order createProduce(String name, String userName, Date deliveryTime){
Date orderTime = new Date();
log.info(userName + "在" + "2019-06-01 12:20:00" + "时间下单成功!预约发货时间为:" + DateUtil.timeFormat(deliveryTime));
Order order = new Order();
new Thread(new Runnable() {
@Override
public void run() {
Product product = new Product(name,userName,deliveryTime,orderTime);
order.setProduct(product);
}
}).start();
return order;
}
private ProductFactory() {}
public static ProductFactory instance(){
if (factory == null){
synchronized (ProductFactory.class){
if (factory == null){
factory = new ProductFactory();
}
}
}
return factory;
}
}
订单
@Slf4j
public class Order {
private Product product;
private boolean complete = false;
public synchronized Product getProduct() {
while (!complete){
try {
wait();
} catch (InterruptedException e) {
log.error("异常了!",e);
}
}
return product;
}
public synchronized void setProduct(Product product) {
if (complete){
return;
}
this.product = product;
complete = true;
notifyAll();
}
}
执行main即可
机制分析
其中FutureTask其实对应的就是Order,Callable对应Product和ProducetFactory。
通过wait和notifyAll机制模拟阻塞获取结果集,如果看Future的实现机制,会发现是通过WaitNode对象和一些状态信息来实现的,比较关键的两个方法set和get方法分别对应Order中的setProduct和getProduct。