sycronize java,java8(异步编程之Future)

Future方法

同步执行

大家好,在Java8之前使用Future的一个例子,例如一个人执行洗衣服和拖地的行为,如果是串行的执行,我们可以用以下的伪代码进行表示

public class FutureTest0 {

public static void main(String[] args) {

long start = System.nanoTime();

System.out.println(Wash());

System.out.println(Sweep());

long duration = (System.nanoTime() - start) / 1000000;

System.out.println(duration);

}

static String Wash() {

try {

Thread.sleep(1000L);

} catch (InterruptedException e) {

e.printStackTrace();

}

return "衣服洗好了";

}

static String Sweep() {

try {

Thread.sleep(1000L);

} catch (InterruptedException e) {

e.printStackTrace();

}

return "地扫好了";

}

}

大家来看下这段代码的执行时间

衣服洗好了

地扫好了

2005 msecs

异步执行

但是在现实生活中我们都知道,洗衣服和扫地这两个行为完全可以并行执行,这就是一个 Future事件,Future相比于底层的Thread更为易用,下面展示了其用法

package com.java8inaction.chapter11.FutureLearn;

import java.util.concurrent.*;

ic class FutureTest0 {

public static void main(String[] args) {

// 创建一个可缓存的线程池

ExecutorService executorService = Executors.newCachedThreadPool();

long start = System.nanoTime();

// 向线程池提交并行任务

Future future = executorService.submit(new Callable() {

@Override

public String call() throws Exception {

// 以异步的方式在新的线程中执行其他任务

return Wash();

}

});

System.out.println(Sweep());

try {

// 设置等待时间为1s,超过这个时间后主线程视这个并行任务阻塞了,就放弃这个任务

String res = future.get(1, TimeUnit.SECONDS);

System.out.println(res);

} catch (InterruptedException e) {

System.out.println("等待过程中任务中断");

e.printStackTrace();

} catch (ExecutionException e) {

System.out.println("计算抛出异常");

e.printStackTrace();

} catch (TimeoutException e) {

System.out.println("并行任务执行超时");

e.printStackTrace();

}

long duration = (System.nanoTime() - start) / 1000000;

System.out.println(duration);

// 关闭线程池

executorService.shutdown();

}

static String Wash() {

try {

Thread.sleep(1000L);

} catch (InterruptedException e) {

e.printStackTrace();

}

return "衣服洗好了";

}

static String Sweep() {

try {

Thread.sleep(1000L);

} catch (InterruptedException e) {

e.printStackTrace();

}

return "地扫好了";

}

}

这段代码是符合了现实生活中人的行为方式,开辟的线程池就相当于洗衣房,我们向洗衣房提交了一个自助洗衣的任务,预定时间是假设是10分钟(代码里以毫秒为单位),在这个时间内我们可以去扫地,扫地大概也是10分钟,所以当10分钟过去后,我们应该也会收到衣服洗好的消息,这样时间就缩短了一半,我们来看下执行的结果

地扫好了

衣服洗好了

1003

但是有一个很现实的问题是,如果我们洗的衣服太多,最后10分钟都不可能洗的完,或者是洗衣机突然崩掉了,我们扫完地又等了很长时间,这种情况在现实编程中很常见,譬如我们异步的去调用一个远程接口,但是这个接口在其自己的进程中执行时突然异常,在这里,Future提供了 Get() 方法,他可以接受一个超时的参数,如果超过这个时间,就会抛出一个TimeoutException 异常,现在我们尝试将代码中执行洗衣服的时间改为4s,可以看到这个超时异常

地扫好了

并行任务执行超时

2007

我们可以用图来描述这整个过程

e767db7eb0ce3351c495deb230269dea.png

改进的CompletableFuture方法

改进的点

在实际现实中,并行任务往往要更复杂,java8之后,出现了一个新的类CompletableFuture,它实现了Future接口,同时适用于更高级的场景

将两个异步计算合并为一个(这两个异步任务相互独立,但第二个又依赖于第一个)

等待Future集合中所有任务都完成

仅仅等待Future集合中最快的任务完成

手动设定异步的操作

当Future完成能收到通知从而进行下一步操作,不再是简单阻塞

同步与异步执行的例子

现在,我们实现一个查询商品价格列表的api,在此过程中,我们增加了一个访问远程获取商品打折券的操作,这里用一个delay() 函数来模拟这个过程

Shop类

package com.java8inaction.chapter11.FutureLearn;

import java.util.Random;

import java.util.concurrent.CompletableFuture;

import java.util.concurrent.Future;

public class Shop {

private String name;

private double price;

public String getName() {return name;}

public void setName(String name) {this.name = name;}

public double getPrice() {return price;}

public Shop(String bestShop) {

this.name = bestShop;

}

// 下面是异步的调用获取打折券方法

public Future getPriceAsync(String product) {

CompletableFuture futurePrice = new CompletableFuture();

new Thread(()->{

try{

// 开始异步计算

double price = calculatePrice(product);

// 设置超时时间

futurePrice.get(1, TimeUnit.SECONDS);

// 完成任务

futurePrice.complete(price);

}catch (Exception e) {

futurePrice.completeExceptionally(e);

}

}).start();

return futurePrice;

}

// 同步调用获取打折券方法

public Double getPriceSycronize(String product) {

double price = calculatePrice(product);

return price;

}

// 模拟去获取打折券

public void getdiscount(){

System.out.println("查询远程打折券数据");

try{

Thread.sleep(2000L);

}catch (InterruptedException e) {

throw new RuntimeException(e);

}

System.out.println("打折券拿到了!");

}

// 获取商品价格

private double calculatePrice(String product) {

delay();

// 随机返回一个价格值

return new Random().nextDouble() * product.charAt(0) + product.charAt(1);

}

// 模拟查询数据库产生的时延

public void delay() {

System.out.println("正在查询数据库...");

try{

Thread.sleep(1000L);

}catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

}

ShopTest类

package com.java8inaction.chapter11.FutureLearn;

import java.util.concurrent.Future;

public class ShopTest {

public static void main(String[] args) {

asyncMethod();

sycronizedMethod();

}

static void asyncMethod() {

System.out.println("开启异步执行...");

Shop shop = new Shop("天猫商城");

long start = System.nanoTime();

Future futurePrice = shop.getPriceAsync("Oranges");

// 执行更多任务

shop.getdiscount();

// 计算商品价格的同时

try{

double price = futurePrice.get();

System.out.printf("查到商品价格为 %.2f%n",price);

}catch (Exception e) {

throw new RuntimeException(e);

}

long retrievalTime = ((System.nanoTime() - start) / 1000000);

System.out.println("耗时 " + retrievalTime + " msecs");

}

static void sycronizedMethod() {

System.out.println("开启同步执行...");

Shop shop = new Shop("天猫商城");

long start = System.nanoTime();

Double price = shop.getPriceSycronize("Oranges");

System.out.printf("查到商品价格为 %.2f%n",price);

shop.getdiscount();

long retrievalTime = ((System.nanoTime() - start) / 1000000);

System.out.println("耗时 " + retrievalTime + " msecs");

}

}

开启异步执行…

查询远程打折券数据

正在查询数据库…

打折券拿到了!

查到商品价格为 188.33

耗时 2058 msecs

开启同步执行…

正在查询数据库…

查到商品价格为 159.73

查询远程打折券数据

打折券拿到了!

耗时 3007 msecs

可以明显看到使用异步api操作带来的效率的提升

当然也可以用函数式语法糖去精简代码

public Future getPriceAsync(String product) {

return CompletableFuture.supplyAsync(() -> calculatePrice(product));

}

本文地址:https://blog.csdn.net/qq_37756310/article/details/110229435

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值