>Future 提前完成任务
首先,梳理一下,多线程为我们带来什么:
- 充分利用CPU
- 当我们需要并行处理一件任务(并不一定是为了提高运算速度,而且很多时候性能并不是绝对的问题,同一时间需要处理多个任务,就要开线程)
Future,未来,什么是未来?
设想一种情景,线程等待生产产品的时候,想做点其他的事情
产品:
public class Product {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + "]";
}
public Product() {
}
public Product(int id, String name) {
this.id = id;
this.name = name;
new Thread(new Runnable() {
@Override
public void run() {
try {
// 模拟产品生产过程
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
生产工厂:
public class ProductFactory {
public Product buildProduct() {
return new Product();
}
}
测试线程:
public class Go {
public static void main(String[] args) {
ProductFactory pf=new ProductFactory();
System.out.println("准备生产产品");
Product product = pf.buildProduct();
System.out.println("生产产品的时候,我想干点别的...");
System.out.println("产品生产完毕"+product);
}
}
结果:
准备生产产品
生产产品的时候,我想干点别的...
产品生产完毕Product [id=1, name=tea]
上面的代码的问题?
首先,为了模拟产品构建比较慢,我们使用Thread.sleep(),然后我们将Thread.sleep() 又放到了一个线程中,这是一种错误的代码,真正模拟生产产品,也就是初始化赋值的代码并没有办法拿到线程里面;
如果不能开线程,那么在真正产品生产结束之前,线程真就不能干点别的。
另外,在构造函数中不能开线程,会造成This 逃逸现象(在对象构造完成之前,就发布了引用)。
再来,新问题:
如果现在要去蛋糕店定做一个蛋糕,蛋糕制作期间,想先处理下其他事情,先拿到订单,做好之后再拿到实际的蛋糕
建立模型:
为什么要设计成这个样子,首先找老板要定做一个蛋糕,需要一个返回值,老板一开始只能给我一个订单,蛋糕和订单 并不是同一个类型,所以要同时继承一个接口/共同继承一个类,这样满足类之间的多态。
其中订单中对蛋糕存在一种包装,存在依赖关系,真正干活的还得是Real。
之前你拿蛋糕是直接在那等着做好了,直接拿蛋糕,现在有了这层 “订单包装”之后,既方便“老板”先给你一个订单,然后开线程把一个未完成的“订单”完成,同时你去做其他事情,也可以通过“订单”这个包装来控制:
- 蛋糕未做完之前,来取就得等待,等做好了就通知你取“蛋糕”。
- 蛋糕做好之后来取,直接就可以获得蛋糕。
/**
* 数据访问接口
*/
public interface Data {
public String obtainString();
}
/**
* 类似于产品 实际数据 "蛋糕"
*/
public class Real implements Data {
public Real() {
try {
//模拟产品生产过程
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public String obtainString() {
//一旦可以调用返回,即代表产品生产完成
return "hello world";
}
}
/**
* 可以理解为 "订单"
*/
public class Future implements Data {
private Real real;
private boolean ready = false;
public synchronized void setReal(Real real) {
if (ready) {
return;
}
this.real = real;
this.ready = true;
notifyAll();
}
@Override
public synchronized String obtainString() {
if (!ready) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return real.obtainString();
}
}
/**
* 返回Data对象 可以理解为 "蛋糕店"
*/
public class RequestHandler {
public Data requestData() {
final Future future = new Future();
//开了一个线程去 做"蛋糕",可以想象这个线程需要运行一段时间
new Thread(new Runnable() {
@Override
public void run() {
Real real = new Real();
future.setReal(real);
}
}).start();
//先给你一个订单
return future;
}
}
public class Go {
public static void main(String[] args) throws InterruptedException {
RequestHandler handler = new RequestHandler();
//这里向"老板"handler 请求做蛋糕 ,拿到订单
Data data1 = handler.requestData();
Data data2 = handler.requestData();
/**
* 这里我们可以做其他事情,而不是等待
*/
System.out.println("我在做其他事情...");
// Thread.sleep(3000);
System.out.println(data1.obtainString());
System.out.println(data2.obtainString());
}
}