async原理(牛逼啊!异步神器:CompletableFuture实现原理和使用场景)

:暂无数据 2026-07-09 15:20:02 1

async原理(牛逼啊!异步神器:CompletableFuture实现原理和使用场景)

其实async原理的问题并不复杂,但是又很多的朋友都不太了解牛逼啊!异步神器:CompletableFuture实现原理和使用场景,因此呢,今天小编就来为大家分享async原理的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!

本文目录

牛逼啊!异步神器:CompletableFuture实现原理和使用场景

CompletableFuture是jdk1.8引入的实现类。扩展了Future和CompletionStage,是一个可以在任务完成阶段触发一些操作Future。简单的来讲就是可以实现异步回调。

对于jdk1.5的Future,虽然提供了异步处理任务的能力,但是获取结果的方式很不优雅,还是需要通过阻塞(或者轮训)的方式。如何避免阻塞呢?其实就是注册回调。

业界结合观察者模式实现异步回调。也就是当任务执行完成后去通知观察者。比如Netty的ChannelFuture,可以通过注册监听实现异步结果的处理。

通过addListener方法注册监听。如果任务完成,会调用notifyListeners通知。

CompletableFuture通过扩展Future,引入函数式编程,通过回调的方式去处理结果。

CompletableFuture的功能主要体现在他的CompletionStage。

可以实现如下等功能

消费和运行的区别:

消费使用执行结果。运行则只是运行特定任务。具体其他功能大家可以根据需求自行查看。

这里举个简单的例子来体验一下他的功能。

执行结果

根据结果我们可以看到会有序执行对应任务。

注意:

这里说明一下,如果是同一任务的依赖任务有多个:

上面的结论是通过阅读源代码得到的。下面我们深入源代码。

创建的方法有很多,甚至可以直接new一个。我们来看一下supplyAsync异步创建的方法。

入参Supplier,带返回值的函数。如果是异步方法,并且传递了执行器,那么会使用传入的执行器去执行任务。否则采用公共的ForkJoin并行线程池,如果不支持并行,新建一个线程去执行。

这里我们需要注意ForkJoin是通过守护线程去执行任务的。所以必须有非守护线程的存在才行。

这里会创建一个用于返回的CompletableFuture。

然后构造一个AsyncSupply,并将创建的CompletableFuture作为构造参数传入。

那么,任务的执行完全依赖AsyncSupply。

在看postComplete方法之前我们先来看一下创建依赖任务的逻辑。

上面提到过。thenAcceptAsync是用来消费CompletableFuture的。该方法调用uniAcceptStage。

uniAcceptStage逻辑:

Mark1逻辑:

这里简单说一下,其实mode有同步异步,和迭代。迭代为了避免无限递归。

这里强调一下d.uniAccept方法的第三个参数。

如果是异步调用(mode》0),传入null。否则传入this。

区别看下面代码。c不为null会调用c.claim方法。

claim方法是逻辑:

this的run任务如下。也就是在异步线程同步调用tryFire方法。达到其被异步线程执行的目的。

看完上面的逻辑,我们基本理解依赖任务的逻辑。

其实就是先判断源任务是否完成,如果完成,直接在对应线程执行以来任务(如果是同步,则在当前线程处理,否则在异步线程处理)

如果任务没有完成,直接返回,因为等任务完成之后会通过postComplete去触发调用依赖任务。

在源任务完成之后会调用。

其实逻辑很简单,就是迭代堆栈的依赖任务。调用h.tryFire方法。NESTED就是为了避免递归死循环。因为FirePost会调用postComplete。如果是NESTED,则不调用。

堆栈的内容其实就是在依赖任务创建的时候加入进去的。上面我们已经提到过。

基本上述源码已经分析了逻辑。

因为涉及异步等操作,我们需要理一下(这里针对全异步任务):

主要是考虑代码的复用。所以逻辑相对难理解。

postComplete方法会被源任务线程执行完源任务后调用。同样也可能被依赖任务线程后调用。

执行依赖任务的方法主要就是靠tryFire方法。因为这个方法可能会被多种不同类型线程触发,所以逻辑也绕一点。(其他依赖任务线程、源任务线程、当前依赖任务线程)

不得不说Doug Lea的编码,真的是艺术。代码的复用性全体现在逻辑上了。

async函数的基本用法

1. async函数的基本形式
//函数声明asyncfunction foo() {}//函数表达式const foo = asyncfunction () {};//对象的方法let obj = { async foo() {} };

obj.foo().then(...)//Class 的方法class Storage {

constructor() {

    this.cachePromise = caches.open(’avatars’);

}

async getAvatar(name) {

    const cache = awaitthis.cachePromise;

    returncache.match(`/avatars/${name}.jpg`);

}

}

const storage =new Storage();

storage.getAvatar(’jake’).then(…);//箭头函数const foo = async () =》 {};
2. async函数的返回值总是一个Promise

无论async函数有无await操作,其总是返回一个Promise。

1. 没有显式return,相当于return Promise.resolve(undefined);

2. return非Promise的数据data,相当于return Promise.resolve(data);

3. return Promise, 会得到Promise对象本身

async总是返回Promise,因此,其后面可以直接调用then方法,

函数内部return返回的值,会成为then回调函数的参数

函数内部抛出的错误,会被then的第二个函数或catch方法捕获到
//正常返回值asyncfunction f(){

    retrun ’hello world’;

}

f().then(v =》 console.log(v));//hello world//抛出错误asyncfunction f(){

    thrownewError(’出错了’);

}

f().then(

    v =》 console.log(v),

    e =》 console.log(e)//Error: 出错了)
3. await操作符的值

= await expression(expression可以是任何值,通常是一个promise)

expression是Promise,rv等于Promise兑现的值,若Promise被拒绝,则抛出异常,由catch捕获

expression是非Promise,会被转换为立即resolve的Promise,rv等于expression

await操作只能用在async函数中,否则会报错。

4. async就是generator和promise的语法糖
//generator写法vargen =function* () {

  varf1 = yield readFile(’/etc/fstab’);

  varf2 = yield readFile(’/etc/shells’);

  console.log(f1.toString());

  console.log(f2.toString());

};//async写法varasyncReadFile = asyncfunction () {

  varf1 = await readFile(’/etc/fstab’);

  varf2 = await readFile(’/etc/shells’);

  console.log(f1.toString());

  console.log(f2.toString());

};
async就是将 generator的 * 换成 async,将 yield 换成 await。

5. async对generator的改进

1. 内置执行器

Generator必须依靠执行器调用next方法来自动执行,例如co模块。而async函数自带执行器,可以自动执行。

2. 更好的语义

async和await分别表示异步和等待,语义更加明确

3. 适用性更强

co模块后面只能是Thunk函数或Promise对象,而await后面可以是Promise或基本数据类型(如:数字,字符串,布尔等)

4. 返回Promise,可以继续操作

async函数总是返回一个Promise对象,可以对其进行then调用,继续操作后面的数据,因此,

async函数完全可以看作是多个Promise合成一个Promise对象,而await命令就是内部的then调用。

6. async内部的并行调用

async配合await都是串行调用,但是若有并行调用,则应按照以下方式来写:

1. 变量分别接收Promise

let fooPromise = getFoo();

let barPromise = getBar();

let foo = await fooPromise();

let bar = await barPromise();

2. 使用Promise.all

let );

Promise.all这种写法有缺陷,一个调用报错,会终止,这个不太符合并行调用的初衷。

3. 使用多个async函数

实际上,一个async函数内部包含的调用应该是强相关的,没有依赖关系的函数调用不应该放在一个async函数中,分开来逻辑更清晰。

4. 并行执行的一些写法

1. 不能再内部非async function中使用await
asyncfunction dbFuc(db) {

  let docs = ;

  // 报错,forEach的function是非async,不能使用awaitdocs.forEach(function (doc) {

    await db.post(doc);

  });

}//这里不需要 asyncfunction dbFuc(db) {

  let docs = ;

  // 可能得到错误结果,这样调用也不能得到正确的结果docs.forEach(asyncfunction (doc) {

    await db.post(doc);

  });

}
2. 循环调用await可以使用for循环或for of循环
//for ofasyncfunction dbFuc(db) {

  let docs = ;

  for (let doc of docs) {

    await db.post(doc);

  }

}//map + Promise.allasyncfunction dbFuc(db) {

  let docs = ;

  let promises = docs.map((doc) =》 db.post(doc));

  let results = await Promise.all(promises);

  console.log(results);

}//map + for ofasyncfunction dbFuc(db) {

  let docs = ;

  let promises = docs.map((doc) =》 db.post(doc));

  let results = ;

  for (let promise of promises) {

    results.push(await promise);

  }

  console.log(results);

}//for循环中去请求网页,若await操作成功,会break退出;若失败,会catch捕获,进入下一轮循环const superagent = require(’superagent’);

const NUM_RETRIES = 3;

async function test() {

  let i;

  for(i = 0; i 《 NUM_RETRIES; ++i) {

    try {

***隐藏网址***

      break;

    } catch(err) {}

  }

  console.log(i); // 3}

test();
7. async的错误处理

使用try...catch进行包裹,例如:
asyncfunction myFunction() {

    try {

        await somethingThatReturnsAPromise();

    } catch (err) {

        console.log(err);

    }

}
如果仅仅对一部分错误进行处理或者忽略,可以局部的进行包裹,或者对单独的promise进行catch,例如:
asyncfunction myFunction() {

    await somethingThatReturnsAPromise().catch((err)=》 {

            console.log(err);

    })

}

async function myFunction() {

    try{

        await somethingThatReturnsAPromise();

    }

    catch(e){}

    await somethingElse();

}
Promise的错误处理,推荐用async + await来写:
// 存值createData(title, successBack, errorBack) {

    // 使用key保存数据    storage.save({

        key: title, 

        data: ’true’,

    }).then(successBack(), errorBack());

}
改写为
//存值async createData1(title, successBack, errorBack) {

    try {

        // 使用key保存数据        await storage.save({

            key: title, 

            data: ’true’,

        });

        successBack()

    } catch (e) {

        errorBack()

    }

}
形式上更加清晰一些。

8. async函数的实现原理

async函数就是将执行器和Generator做为一个整体返回。
asyncfunction fn(){}//等同于function fn(){

    returnspawn(function* (){

    })

}
spawn的实现
function spawn(genF) {

    /****

    * 返回的是一个promise

    */returnnewPromise(function(resolve, reject) {

        vargen=genF();//运行Generator这个方法;/***

        * 执行下一步的方法

        * @param fn 一个调用Generator方法的next方法

        */function step(fn) {

            //如果有错误,则直接返回,不执行下面的awaittry {

            varnext=fn();

            }catch (e){

            return reject(e)

            }

            //如果下面没有yield语句,即Generator的done是trueif(next.done){

            return resolve(next.value);

            }

            Promise.resolve(next.value).then((val)=》{

                step(function(){return gen.next(val) } )

            }).catch((e)=》{

                step(function(){returngen.throw(e) } )

            })

        }

        step(function () {

            return gen.next();

        })

    });

}

参考自 async的基本用法 - 看风景就 - 博客园

关于本次async原理和牛逼啊!异步神器:CompletableFuture实现原理和使用场景的问题分享到这里就结束了,如果解决了您的问题,我们非常高兴。

async原理(牛逼啊!异步神器:CompletableFuture实现原理和使用场景)

本文编辑:admin

更多文章:


数据库管理系统和数据库系统分别侧重(数据库,数据库管理系统,数据库系统,这三个分别是什么意思并举个实例)

数据库管理系统和数据库系统分别侧重(数据库,数据库管理系统,数据库系统,这三个分别是什么意思并举个实例)

今天给各位分享数据库,数据库管理系统,数据库系统,这三个分别是什么意思并举个实例的知识,其中也会对数据库,数据库管理系统,数据库系统,这三个分别是什么意思并举个实例进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

2026年9月7日 17:00

编程语言出现的先后顺序(最早的编程语言是哪一个)

编程语言出现的先后顺序(最早的编程语言是哪一个)

今天给各位分享最早的编程语言是哪一个的知识,其中也会对最早的编程语言是哪一个进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

2026年9月7日 16:10

小程序源码有什么用(大商创小程序源码好用吗)

小程序源码有什么用(大商创小程序源码好用吗)

“小程序源码有什么用”相关信息最新大全有哪些,这是大家都非常关心的,接下来就一起看看小程序源码有什么用(大商创小程序源码好用吗)!

2026年9月7日 15:40

springmvc的依赖(springMVC的注入方式有哪几种,这与springMVC依赖)

springmvc的依赖(springMVC的注入方式有哪几种,这与springMVC依赖)

大家好,关于springmvc的依赖很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于springMVC的注入方式有哪几种,这与springMVC依赖的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还

2026年9月7日 14:00

it培训评价网(it培训排名机构十大IT培训机构)

it培训评价网(it培训排名机构十大IT培训机构)

这篇文章给大家聊聊关于it培训评价网,以及it培训排名机构十大IT培训机构对应的知识点,希望对各位有所帮助,不要忘了收藏本站哦。

2026年9月7日 13:00

个人博客页面布局(新手站长怎样做好独立博客初期运营工作)

个人博客页面布局(新手站长怎样做好独立博客初期运营工作)

大家好,如果您还对个人博客页面布局不太了解,没有关系,今天就由本站为大家分享个人博客页面布局的知识,包括新手站长怎样做好独立博客初期运营工作的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!

2026年9月7日 12:40

display flex 自动换行(overflow-y:hidden;overflow-x:auto;无效解决方法)

display flex 自动换行(overflow-y:hidden;overflow-x:auto;无效解决方法)

大家好,关于display flex 自动换行很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于overflow-y:hidden;overflow-x:auto;无效解决方法的知识点,相信应该可以解决大家的一些困惑和问题,如

2026年9月7日 11:00

小程序免认证源码(小程序源码都能干嘛)

小程序免认证源码(小程序源码都能干嘛)

本篇文章给大家谈谈小程序免认证源码,以及小程序源码都能干嘛对应的知识点,文章可能有点长,但是希望大家可以阅读完,增长自己的知识,最重要的是希望对各位有所帮助,可以解决了您的问题,不要忘了收藏本站喔。

2026年9月7日 10:50

timestamp without time zone(Postgresql中to_date()函数使用问题)

timestamp without time zone(Postgresql中to_date()函数使用问题)

各位老铁们好,相信很多人对timestamp without time zone都不是特别的了解,因此呢,今天就来为大家分享下关于timestamp without time zone以及Postgresql中to_date()函数使用问题

2026年9月7日 09:40

网页制作代码特效大全(谁知道网页打字机特效的代码)

网页制作代码特效大全(谁知道网页打字机特效的代码)

大家好,如果您还对网页制作代码特效大全不太了解,没有关系,今天就由本站为大家分享网页制作代码特效大全的知识,包括谁知道网页打字机特效的代码的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!

2026年9月7日 04:20

最近更新

创业加盟网1688(怎样考察加盟店)
2026-09-07 17:50:14 浏览:0
热门文章

yoga pro 14s carbon(yoga14s接口类型)
2026-07-03 17:50:01 浏览:5
domino directory(帮我翻译一下Recipient’s Domino Directory entry does not specify a valid Notes mail file)
2026-08-03 19:20:01 浏览:4
标签列表