异步编程还得看JDK8

什么是异步编程

在很多时候,我们在进程中使用单一线程从头到尾地执行程序,比如程序向另外一台服务器发出请求,由于网络等外部原因,此种通信任务往往会耗费大量时间,进程如果在此期间仅仅只能等待网络或网络上其他机器的响应,将严重地降低了性能。

创新互联服务紧随时代发展步伐,进行技术革新和技术进步,经过10年的发展和积累,已经汇集了一批资深网站策划师、设计师、专业的网站实施团队以及高素质售后服务人员,并且完全形成了一套成熟的业务流程,能够完全依照客户要求对网站进行网站设计、成都网站建设、建设、维护、更新和改版,实现客户网站对外宣传展示的首要目的,并为客户企业品牌互联网化提供全面的解决方案。

如果程序调用某个方法,等待其执行全部处理后才能继续执行,我们称其为同步的。相反,在处理完成之前就返回调用方法则是异步的。

我们在编程语言的流程中添加了异步控制的部分,这部分的编程可以称之为异步编程。

JDK中的异步编程

Future

Future模式在 JDK5 的时候就有, Future模式,只是发起了耗时操作,函数立马就返回了,真正执行具体操作由另外一个工作线程去完成,并不会阻塞客户端线程。所以在工作线程执行耗时操作的时候客户端无需等待,可以继续做其他事情,等到需要的时候再向工作线程获取结果。

举个最简单的例子,我们烧水的时候么,不用一直在炉子旁边看着,在烧水的过程中,我们需要做一些其他的事情,比如去写一会代码,但是在你去写代码之前,会给你一个假的结果,比如,我已经烧开了,但是,在你去写代码的时候,他就开始疯狂加火,等到水烧开为止,等到你口渴想倒水的时候,发现水是已经烧开的,也就是说,当你在写代码之前的时候收到的是个假的结果。

实际上,Future 模式无法立即给出你想要的结果,但它会给你一个契约,之后你可以随时通过这个契约来获取你想要的结果。

异步模式主要是和同步模式进行对比的,我们画个图来看看。

黄色区域的位置的Y轴长度则表示的是你需要等待的所有时间,在这个时间内,你没有办法做任何的事情,只能在这里等着,但是异步的话,就完全不用这个样子了。

在JDK中Future模式有一套完整的实现。

我们来写案例代码实验一下:

没有是用 Future 的代码。

NormalThreadTest

public class NormalThreadTest {

public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
// 开启购买厨具线程
ShoppingThread shopping = new ShoppingThread();
shopping.start();
shopping.join(); // 保障厨具购买并送货
// 获取到购买厨具
KitchenWare kc = shopping.kc;

// 买食材
FoodMaterial fm = new FoodMaterial();
Thread.sleep(2000);
System.out.println("第二步: 食材已经到位");
// 烹饪美食
cooking(kc, fm);
System.out.println("第三步: 美食烹饪完成");
long end = System.currentTimeMillis();
System.out.println("烹饪美食时间为:" + (end - start));
}


/**
* 定义网上购物厨具线程
* @author Administrator
*
*/
static class ShoppingThread extends Thread {

// 厨具对象引用
private KitchenWare kc;

@Override
public void run() {
System.out.println("第一步: 网上下单");
System.out.println("第一步: 等待厨具");
try {
Thread.sleep(5000); // 等待厨具时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一步: 快递送货");
// 生产厨具
kc = new KitchenWare();
}
}

/**
* 厨具类
* @author Administrator
*
*/
static class KitchenWare {

}

/**
* 食材类
* @author Administrator
*
*/
static class FoodMaterial {

}

/**
* 定义烹饪食物的方法
* @param kc
* @param fm
*/
static void cooking(KitchenWare kc, FoodMaterial fm) {

}
}

运行结果:

第一步: 网上下单
第一步: 等待厨具
第一步: 快递送货
第二步: 食材已经到位
第三步: 美食烹饪完成
烹饪美食时间为:7043

已经使用Future的代码。

FutureThreadTest

public class FutureThreadTest {


public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();

Callable callable = new Callable() {
public KitchenWare call() throws Exception {
System.out.println("第一步: 网上下单");
System.out.println("第一步: 等待厨具");
try {
Thread.sleep(5000); // 等待厨具时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第一步: 快递送货");
return new KitchenWare();
}

};
// 包装为异步执行的对象
FutureTask task = new FutureTask<>(callable);
new Thread(task).start();

// 买食材
FoodMaterial fm = new FoodMaterial();
Thread.sleep(2000);
System.out.println("第二步: 食材已经到位");

if (!task.isDone()) {
System.out.println("厨具还没有到.....");
}
// 通过阻塞形式获取到异步块执行的结果
KitchenWare kc = task.get(); // 阻塞
// 烹饪美食
cooking(kc, fm);
System.out.println("第三步: 美食烹饪完成");
long end = System.currentTimeMillis();
System.out.println("烹饪美食时间为:" + (end - start));
}


/**
* 厨具类
* @author Administrator
*
*/
static class KitchenWare {

}

/**
* 食材类
* @author Administrator
*
*/
static class FoodMaterial {

}

/**
* 定义烹饪食物的方法
* @param kc
* @param fm
*/
static void cooking(KitchenWare kc, FoodMaterial fm) {

}
}

执行结果:

第一步: 网上下单
第一步: 等待厨具
第二步: 食材已经到位
厨具还没有到.....
第一步: 快递送货
第三步: 美食烹饪完成
烹饪美食时间为:5027

这个是JDK5中就有的 Future 来实现 异步编程的,那么接下来我们看1.8的异步编程。

CompletableFuture

Future 虽然可以实现获取异步执行结果的需求,但是它没有提供通知的机制,我们无法得知Future什么时候完成,我们通过上面的代码也完全能看出来。

为什么在JDK5之后,又推出新的异步编程,因为使用 Future 要么使用阻塞,在 future.get() 的地方等待 Future 返回的结果,这时又变成同步操作。要么使用 isDone() 轮询地判断 Future 是否完成,这样会耗费CPU的资源。所以阿粉猜测所以在JDK8又推出了 CompletableFuture。

之前 Future 需要等待 isDone 为 true 才能知道任务跑完了。或者就是用 get 方法调用的时候会出现阻塞。而使用 CompletableFuture 的使用就可以用 then , when 等等操作来防止以上的阻塞和轮询 isDone 的现象出现。

CompletableFuture 有四个方法来创建CompletableFuture对象。

public static CompletableFuture   runAsync(Runnable runnable)

public static CompletableFuture runAsync(Runnable runnable, Executor executor)

public static CompletableFuture supplyAsync(Supplier supplier)

public static CompletableFuture supplyAsync(Supplier supplier, Executor executor)

Asynsc表示异步,而supplyAsync与runAsync不同在与前者异步返回一个结果,后者是void.第二个函数第二个参数表示是用我们自己创建的线程池,否则采用默认的ForkJoinPool.commonPool()作为它的线程池.其中Supplier是一个函数式接口,代表是一个生成者的意思,传入0个参数,返回一个结果。

我们写一个最简单的测试代码:

public static void test2() throws Exception {
//supplyAsync内部使用ForkJoinPool线程池执行任务
CompletableFuture completableFuture=CompletableFuture.supplyAsync(()->{
//模拟执行耗时任务
System.out.println("task doing...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//返回结果
return "100";
}).whenComplete((v,r)->{
System.out.println("计算结果是: "+v);
});
//CompletableFuture里使用的线程池里的线程默认是daemon的。main线程结束后,整个程序也
//结束了,这里将main线程join后任务里的代码才可以执行完
Thread.currentThread().join();
}

而使用 CompletableFuture 能有效的避开使用 Futrue 出现的缺点。

看来,JDK 每一次的更新换代,不光是加了一些新的内容,而且像开发一样,每次迭代的时候,同时也会更新之前的一些不完美的内容,不是么?

名称栏目:异步编程还得看JDK8
路径分享:http://www.shufengxianlan.com/qtweb/news36/1236.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联