精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Java 異步編程:從 Future 到 Loom

新聞 前端
眾所周知,Java 開始方法執(zhí)行到結(jié)束,都是由同一個(gè)線程完成的。這種方式雖易于開發(fā)調(diào)試,但容易因?yàn)殒i、IO 等原因?qū)е戮€程掛起,產(chǎn)生線程上下文切換。

 眾所周知,Java 開始方法執(zhí)行到結(jié)束,都是由同一個(gè)線程完成的。這種方式雖易于開發(fā)調(diào)試,但容易因?yàn)殒i、IO 等原因?qū)е戮€程掛起,產(chǎn)生線程上下文切換。隨著對應(yīng)用并發(fā)能力要求越來越高,頻繁的線程上下文切換所帶來的成本變得難以忽視。同時(shí),線程也是相對寶貴的資源,無限制的增加線程是不可能的。優(yōu)秀的技術(shù)人員應(yīng)該能讓應(yīng)用使用更少的線程資源實(shí)現(xiàn)更高的并發(fā)能力。這便是我們今天要討論的話題 —— Java 異步編程技術(shù)。

異步編程其實(shí)并沒有清晰定義。通常我們認(rèn)為,從方法開始到結(jié)束都必須在同一個(gè)線程內(nèi)調(diào)度執(zhí)行的編程方式可被認(rèn)為是同步編程方式。但因?yàn)檫@樣的方式是我們習(xí)以為常的,所以也就沒有專門名字去稱呼它。與這種同步方式相對的,便是異步。即方法的開始到結(jié)束可以由不同的線程調(diào)度執(zhí)行的編程方式,被成為異步編程。

異步編程技術(shù)目的,重點(diǎn)并非提高并發(fā)能力,而是提高伸縮性 (Scalability)。現(xiàn)在的 Web 服務(wù),應(yīng)付 QPS 幾百上千,甚至上萬的場景并沒有太大問題,但問題是如何在并發(fā)請求量突增的場景中提供穩(wěn)定服務(wù)呢?如果一個(gè)應(yīng)用能穩(wěn)定提供 QPS 1000的服務(wù)。假如在某一個(gè)大促活動中,這個(gè)應(yīng)用的 QPS 突然增加到10000怎么辦?或者 QPS 沒變,但這個(gè)應(yīng)用所依賴的服務(wù)發(fā)生故障,或網(wǎng)絡(luò)超時(shí)。當(dāng)這些情況發(fā)生時(shí),服務(wù)還能穩(wěn)定提供嗎?雖然熔斷、限流等技術(shù)能夠解決這種場景下服務(wù)的可用性問題,但這畢竟是一種舍車保帥的做法。是否能在流量突增時(shí)仍保證服務(wù)質(zhì)量呢?答案是肯定的,那就是異步編程 + NIO。NIO 技術(shù)本身現(xiàn)在已經(jīng)很成熟了,關(guān)鍵是用一種什么樣的異步編程技術(shù)將 NIO 落地到系統(tǒng),尤其是業(yè)務(wù)快速迭代的前臺、中臺系統(tǒng)中。

這就是本文討論 Java 異步編程的原因。Java 應(yīng)用開發(fā)領(lǐng)域究竟有哪些技術(shù)可以用來提升系統(tǒng)的伸縮性?本文將按照這些技術(shù)的演化歷程,介紹一下這些技術(shù)的意義和演化過程:

  • Future
  • Callback
  • Servlet 3.0
  • 反應(yīng)式編程
  • Kotlin 協(xié)程
  • Project Loom

一、Future

J.U.C 中的 Future 算是 Java 對異步編程的第一個(gè)解決方案。當(dāng)向線程池 submit 一個(gè)任務(wù)后,這個(gè)任務(wù)便被另一個(gè)線程執(zhí)行了:

  1. Future future = threadPool.submit(() -> {  foobar();  return result;});Object result = future.get(); 

但這個(gè)解決方案有很多缺陷:

  1. 無法方便得知任務(wù)何時(shí)完成
  2. 無法方便獲得任務(wù)結(jié)果
  3. 在主線程獲得任務(wù)結(jié)果會導(dǎo)致主線程阻塞

二、Callback

為了解決使用 Future 所存在的問題,人們提出了一個(gè)叫 Callback 的解決方案。比如 Google Guava 包中的 ListenableFuture 就是基于此實(shí)現(xiàn)的:

  1. ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {  public Explosion call() {    return pushBigRedButton();  }});Futures.addCallback(explosion, new FutureCallback<Explosion>() {  // we want this handler to run immediately after we push the big red button!  public void onSuccess(Explosion explosion) {    walkAwayFrom(explosion);  }  public void onFailure(Throwable thrown) {    battleArchNemesis(); // escaped the explosion!  }}); 

通過執(zhí)行 ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {}) 創(chuàng)建異步任務(wù)。通過 Futures.addCallback(explosion, new FutureCallback<Explosion>() {} 添加處理結(jié)果的回調(diào)函數(shù)。這樣避免獲取并處理異步任務(wù)執(zhí)行結(jié)果阻塞調(diào)起線程的問題。Callback 是將任務(wù)執(zhí)行結(jié)果作為接口的入?yún)ⅲ谌蝿?wù)完成時(shí)回調(diào) Callback 接口,執(zhí)行后續(xù)任務(wù),從而解決純 Future 方案無法方便獲得任務(wù)執(zhí)行結(jié)果的問題。

但 Callback 產(chǎn)生了新的問題,那就是代碼可讀性的問題。因?yàn)槭褂?Callback 之后,代碼的字面形式和其所表達(dá)的業(yè)務(wù)含義不匹配,即業(yè)務(wù)的先后關(guān)系到了代碼層面變成了包含和被包含的關(guān)系。

因此,如果大量使用 Callback 機(jī)制,將使大量的應(yīng)該是先后的業(yè)務(wù)邏輯在代碼形式上表現(xiàn)為層層嵌套。這會導(dǎo)致代碼難以理解和維護(hù)。這便是所謂的 Callback Hell(回調(diào)地獄)問題。

Callback Hell 問題可以從兩個(gè)方向進(jìn)行一定的解決:一是事件驅(qū)動機(jī)制、二是鏈?zhǔn)秸{(diào)用。前者被如 Vert.x 所使用,后者被 CompletableFuture、反應(yīng)式編程等技術(shù)采用。但這些優(yōu)化的效果有限,不能根本上解決 Callback 機(jī)制所帶來的代碼可維護(hù)性的下降。

Callback 與 NIO

Callback 真正體現(xiàn)價(jià)值,是它與 NIO 技術(shù)結(jié)合之后。原因也很簡單:對于 CPU 密集型應(yīng)用,采用 Callback 風(fēng)格沒有意義;對于 IO 密集型應(yīng)用,如果是使用 BIO,Callback 同樣沒有意義,因?yàn)樽罱K會有一個(gè)線程是因?yàn)?IO 而阻塞。而只有使用 NIO 才能避免線程阻塞,也必須使用 Callback 風(fēng)格,才能使應(yīng)用得以被開發(fā)出來。NIO 的廣泛應(yīng)用是在 Apache Mina、JBoss Netty 等技術(shù)出現(xiàn)之后。這些技術(shù)很大程度地簡化了 NIO 技術(shù)的使用,但直接使用它們開發(fā)業(yè)務(wù)系統(tǒng)還是很繁瑣。

下面看一個(gè)真實(shí)的例子。這個(gè)例子背后的完整應(yīng)用的功能是將微軟 Exchange 服務(wù)接口(Exchange Web Service)轉(zhuǎn)換為 Rest 風(fēng)格的接口,下面這段代碼是這個(gè)應(yīng)用的一部分。

  1. public class EwsCalendarHandler extends ChannelInboundHandlerAdapter {    @Override    public void channelRead(final ChannelHandlerContext ctx, Object msg) {        if (msg instanceof HttpRequest) {            final HttpRequest origReq = (HttpRequest) msg;            HttpRequest request = translateRequest(origReq);            if (backendChannel == null) {                connectBackendFuture = connectBackend(ctx, StaticConfiguration.EXCHANGE_PORT);                sendMessageAfterConnected(ctx, request);            } else if (backendChannel.isActive()) {                setHttpRequestToBackendHandler(request);                sendObjectAndFlush(ctx, request);            } else {                sendMessageAfterConnected(ctx, request);            }        } else if (msg instanceof HttpContent) {            HttpContent content = (HttpContent) msg;            if (backendChannel == null || !backendChannel.isActive()) {                sendMessageAfterConnected(ctx, content);            } else {                sendObjectAndFlush(ctx, content);            }        }    }        private void sendMessageAfterConnected(final ChannelHandlerContext ctx, final HttpObject message) {        if (connectBackendFuture == null) {            LOGGER.warn("next hop connect future is null, drop the message and return: {}", message);            return;        }        connectBackendFuture.addListener((ChannelFutureListener) future -> {            if (future.isSuccess()) {                ChannelFuture f = sendObjectAndFlush(ctx, message);                if (f != null) {                    f.addListener((future1) ->                            backendChannel.attr(FIND_ITEM_START_ATTR_KEY).set(System.currentTimeMillis())                    );                }            }        });    }} 

在方法 sendMessageAfterConnected 中,我們已經(jīng)能看到嵌套兩層的 Callback。而上面實(shí)例中的 EwsCalendarHandler 所實(shí)現(xiàn)的 ChannelInboundHandler 接口,本質(zhì)上也是一個(gè)回調(diào)接口。

其實(shí)上面的例子只有一級服務(wù)調(diào)用。在微服務(wù)流行的今天,多級服務(wù)調(diào)用很常見,一個(gè)服務(wù)先調(diào) A,再用結(jié)果 A 調(diào) B,然后用結(jié)果 B 調(diào)用 C,等等。這樣的場景,如果直接用 Netty 開發(fā),技術(shù)難度會比傳統(tǒng)方式增加很多。這其中的難度來自兩方面,一是 NIO 和 Netty 本身的技術(shù)難度,二是 Callback 風(fēng)格所導(dǎo)致的代碼理解和維護(hù)的困難。

因此,直接使用 Netty,通常局限在基礎(chǔ)架構(gòu)層面,在前臺和中臺業(yè)務(wù)系統(tǒng)中,應(yīng)用較少。

三、Servlet 3.0

上面講到,如果直接使用 Netty 開發(fā)應(yīng)用,將不可避免地遇到 Netty 和 NIO 本身的技術(shù)挑戰(zhàn),以及 Callback Hell 問題。對于前者,Servlet 3.0 提供了一個(gè)解決方案。

▼ 示例:Servlet 3.0 ▼

  1. @WebServlet(urlPatterns = "/demo", asyncSupported = true)public class AsyncDemoServlet extends HttpServlet {    @Override    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {        // Do Something         AsyncContext ctx = req.startAsync();        startAsyncTask(ctx);    }} private void startAsyncTask(AsyncContext ctx) {    requestRpcService(result -> {        try {            PrintWriter out = ctx.getResponse().getWriter();            out.println(result);            out.flush();            ctx.complete();        } catch (Exception e) {            e.printStackTrace();        }    });} 

Servlet 3.0 的出現(xiàn),解決了在過去基于 Servlet 的 Web 應(yīng)用中,接受請求和返回響應(yīng)必須在同一個(gè)線程的問題,實(shí)現(xiàn)了如下目標(biāo):

  1. 可以避免了 Web 容器的線程被阻塞掛起
  2. 使請求接收之后的任務(wù)處理可由專門線程完成
  3. 不同任務(wù)可以實(shí)現(xiàn)線程池隔離
  4. 結(jié)合 NIO 技術(shù)實(shí)現(xiàn)更高效的 Web 服務(wù)

除了直接使用 Servlet 3.0,也可以選擇 Spring MVC 的 Deferred Result。

▼ 示例:Spring MVC DeferredResult ▼

  1. @GetMapping("/async-deferredresult")public DeferredResult<ResponseEntity<?>> handleReqDefResult(Model model) {    LOG.info("Received async-deferredresult request");    DeferredResult<ResponseEntity<?>> output = new DeferredResult<>();         ForkJoinPool.commonPool().submit(() -> {        LOG.info("Processing in separate thread");        try {            Thread.sleep(6000);        } catch (InterruptedException e) {        }        output.setResult(ResponseEntity.ok("ok"));    });         LOG.info("servlet thread freed");    return output;} 

Servlet 3.0 的技術(shù)局限

Servlet 3.0 并不是用來解決前面提到的 Callback Hell 問題的,它只是降低了異步 Web 編程的技術(shù)門檻。對于 Callback Hell 問題,使用 Servlet 3.0 或類似技術(shù)時(shí)同樣會遇到。解決 Callback Hell 還需另尋他法。

四、反應(yīng)式編程

現(xiàn)在擋在異步編程最大的障礙就是 Callback Hell,因?yàn)?Callback Hell 對代碼可讀性有很大殺傷力。而本節(jié)介紹的反應(yīng)式編程技術(shù),除了響應(yīng)性、伸縮性、容錯性以外,從開發(fā)人員的角度來講,就是代碼可讀性要比 Callback 提升了許多。

▼ 圖:反應(yīng)式編程的特性 ▼

Java 異步編程:從 Future 到 Loom

▼ 反應(yīng)式編程簡單示例 ▼

  1. userService.getFavorites(userId)           .flatMap(favoriteService::getDetails)           .switchIfEmpty(suggestionService.getSuggestions())           .take(5)           .publishOn(UiUtils.uiThreadScheduler())           .subscribe(uiList::show, UiUtils::errorPopup); 

可讀性的提高原因在于反應(yīng)式編程可讓開發(fā)人員將實(shí)現(xiàn)業(yè)務(wù)的各種方法使用鏈?zhǔn)剿阕哟?lián)起來,而串聯(lián)起來的各種方法的先后關(guān)系與執(zhí)行順序大體一致。

這其實(shí)是采用了函數(shù)式編程的設(shè)計(jì),通過函數(shù)式編程解決了之前 Callback 設(shè)計(jì)存在的代碼可讀性問題。

雖然相對于 Callback,代碼可讀性是反應(yīng)式編程的優(yōu)點(diǎn),但這種優(yōu)點(diǎn)是相對的,相對于傳統(tǒng)代碼,可讀性就成了反應(yīng)式編程的缺點(diǎn)。上面的例子代碼看上去還容易理解,但換成下面的例子,大家就又能重新看到 Callback Hell 的影子了:

▼ 示例:查詢最近郵件數(shù)(反應(yīng)式編程版) ▼

  1. @GetMapping("/reactive/{personId}")fun getMessagesFor(@PathVariable personId: String): Mono<String> {  return peopleRepository.findById(personId)      .switchIfEmpty(Mono.error(NoSuchElementException()))      .flatMap { person ->          auditRepository.findByEmail(person.email)              .flatMap { lastLogin ->                  messageRepository.countByMessageDateGreaterThanAndEmail(lastLogin.eventDate, person.email)                      .map { numberOfMessages ->                          "Hello ${person.name}, you have $numberOfMessages messages since ${lastLogin.eventDate}"                      }              }      }} 

因此,反應(yīng)式編程只看代碼形式,可以被視為 Callback 2.0。解決了之前的一些問題,但并不徹底。

目前,在 Java 領(lǐng)域?qū)崿F(xiàn)了反應(yīng)式編程的技術(shù)有 Spring 的 Project Reactor、Netflix RxJava 1/2 等。前者的 3.0 版本作為 Spring 5 的基礎(chǔ),在17年底發(fā)布,推動了后端領(lǐng)域反應(yīng)式編程的發(fā)展。后者出現(xiàn)時(shí)間更早,在前端開發(fā)領(lǐng)域應(yīng)用的比后端更要廣泛一些。

除了開源框架,JDK 也提供了對反應(yīng)式編程解決方案:JDK 8 的 CompletableFuture 不算是反應(yīng)式編程,但是它在形式上帶有一些反應(yīng)式編程的函數(shù)式代碼風(fēng)格。JDK 9 Flow 實(shí)現(xiàn)了 Reactive Streams 規(guī)范,但是實(shí)施反應(yīng)式編程需要完整的解決方案,單靠 Flow 是不夠的,還是需要 Project Reactor 這樣的完整解決方案。但 JDK 層面的技術(shù)能提供統(tǒng)一的技術(shù)抽象和實(shí)現(xiàn),在統(tǒng)一技術(shù)方面還是有積極意義的。

反應(yīng)式編程的應(yīng)用范圍

正如前面所說,反應(yīng)式編程仍然存在代碼可讀性的問題,這個(gè)問題在加上反應(yīng)式編程本身的技術(shù)門檻,使得用反應(yīng)式編程技術(shù)在業(yè)務(wù)系統(tǒng)開發(fā)領(lǐng)域一直沒有流行普及。但是對于核心系統(tǒng)、底層系統(tǒng),反應(yīng)式編程技術(shù)所帶來的伸縮性、容錯性的提升同其增加的開發(fā)成本相比通常是可以接受。因此核心系統(tǒng)、底層系統(tǒng)是適合采用反應(yīng)式編程技術(shù)的。

五、Kotlin 協(xié)程

前面介紹的各種技術(shù),都有明顯的缺陷:Future 不是真異步;Callback 可讀性差;Servlet 3.0 等技術(shù)沒能解決 Callback 的缺陷;反應(yīng)式編程還是難以編寫復(fù)雜業(yè)務(wù)。到了18年,一種新的 JVM 編程語言開始流行:Kotlin。Kotlin 首先流行在 Android 開發(fā)領(lǐng)域,因?yàn)樗玫搅?Google 的首肯和支持。但對于后端開發(fā)領(lǐng)域,因?yàn)橐豁?xiàng)特性,使得 Kotlin 也非常值得注意。那就是 Kotlin Coroutine(后文稱 Kotlin 協(xié)程)。對于這項(xiàng)技術(shù),我已經(jīng)寫過三篇文章,分別介紹入門、原理和與 Spring Project Reactor 的整合方式。感興趣的同學(xué)可以去我的簡書和微信公眾號上去看這些文章(搜索“編走編想”)。

協(xié)程技術(shù)不是什么新技術(shù),它在很多語言中都有實(shí)現(xiàn),比如大家所熟悉的 Python、Lua、Go 都是支持協(xié)程的。在不同語言中,協(xié)程的實(shí)現(xiàn)方法各有不同。因?yàn)?Kotlin 的運(yùn)行依賴于 JVM,不能對 JVM 進(jìn)行修改,因此,Kotlin 不能在底層支持協(xié)程。同時(shí),Kotlin 是一門編程語言,需要在語言層面支持協(xié)程,而不是像框架那樣在語言層面之上支持。因此,Kotlin 對協(xié)程支持最核心的部分是在編譯器中。因?yàn)閷@部分原理的解釋在之前文章中都有涉及,因此不在這里重復(fù)。

使用 Kotlin 協(xié)程之后最大的好處是異步代碼的可讀性大大提高。如果上一個(gè)示例用 Kotlin 協(xié)程實(shí)現(xiàn),那就是下面的樣子:

▼ 示例:查詢最近郵件數(shù)(Kotlin 協(xié)程版) ▼

  1. @GetMapping("/coroutine/{personId}")fun getNumberOfMessages(@PathVariable personId: String) = mono(Unconfined) {    val person = peopleRepository.findById(personId).awaitFirstOrDefault(null)            ?: throw NoSuchElementException("No person can be found by $personId")    val lastLoginDate = auditRepository.findByEmail(person.email).awaitSingle().eventDate    val numberOfMessages =            messageRepository.countByMessageDateGreaterThanAndEmail(lastLoginDate, person.email).awaitSingle()    "Hello ${person.name}, you have $numberOfMessages messages since $lastLoginDate"

目前在 Spring 應(yīng)用中使用 Kotlin 協(xié)程還有些小繁瑣,但在 Spring Boot 2.2 中,可以直接在 Spring WebFlux 方法上使用 suspend 關(guān)鍵字。

Kotlin 協(xié)程最大的意義就是可以用看似指令式編程方式(Imperative Programming

,即傳統(tǒng)編程方式)去寫異步編程代碼。并發(fā)和代碼可讀性似乎兩全其美了。

Kotlin 協(xié)程的局限性

但事情不是那么完美。Kotlin 協(xié)程依賴于各種基于 Callback 的技術(shù)。像上面的例子,之所以可以用 Kotlin 協(xié)程,是因?yàn)樯弦粋€(gè)版本使用了反應(yīng)式編程技術(shù)。所以,只有當(dāng)一段代碼使用了 ListenableFuture、CompletableFuture、Project Reactor、RxJava 等技術(shù)時(shí),才能用 Kotlin 協(xié)程進(jìn)行改造優(yōu)化。那對于其它的會阻塞線程的技術(shù),如 Object.wait、Thread.sleep、Lock、BIO 等,Kotlin 協(xié)程就無能為力了。

另外一個(gè)局限性源于 Kotlin 本身。雖然 Kotlin 兼容 Java,但這種兼容并非完美。因此,對于組件,尤其是基礎(chǔ)組件的開發(fā),并不推薦使用 Kotlin,而是更推薦使用 Java。這也導(dǎo)致 Kotlin 協(xié)程的使用范圍被進(jìn)一步地限制。

六、Project Loom

前面講到,雖然 Kotlin 協(xié)程看上去很好,但在使用上還是有著種種限制。那有沒有更好的選擇呢?答案是 Project Loom (https://openjdk.java.net/projects/loom/)。這個(gè)項(xiàng)目在18年底的時(shí)候已經(jīng)達(dá)到可初步演示的原型階段。不同于之前的方案,Project Loom 是從 JVM 層面對多線程技術(shù)進(jìn)行徹底的改變。

Project Loom 設(shè)計(jì)思想與之前的一個(gè)開源 Java 協(xié)程技術(shù)非常相似。這個(gè)技術(shù)就是 Quasar Fiber https://docs.paralleluniverse.co/quasar/ 。而現(xiàn)在 Project Loom 的主要設(shè)計(jì)開發(fā)人員 Ron Pressler 就是來自 Quasar Fiber。

這里建議大家讀一下 Project Loom 的這篇文檔:http://cr.openjdk.java.net/~rpressler/loom/Loom-Proposal.html。這篇文檔介紹了發(fā)起 Project Loom 的原因,以及 Java 線程基礎(chǔ)的很多底層設(shè)計(jì)。

其實(shí)發(fā)起 Project Loom 的原因也很簡單:長期以來,Java 的線程是與操作系統(tǒng)的線程一一對應(yīng)的,這限制了 Java 平臺并發(fā)能力的提升。各種框架或其它 JVM 編程語言的解決方案,都在使用場景上有限制。例如 Kotlin 協(xié)程必須基于各種 Callback 技術(shù),而 Callback 技術(shù)有存在編寫、調(diào)試?yán)щy的問題。為了使 Java 并發(fā)能力在更大范圍上得到提升,從底層進(jìn)行改進(jìn)便是必然。

下面這幅圖很好地展示了目前 Java 并發(fā)編程方面的困境,簡單的代碼并發(fā)、伸縮能力差;并發(fā)、伸縮能力強(qiáng)的代碼復(fù)雜,難以與現(xiàn)有代碼整合。

Java 異步編程:從 Future 到 Loom

為了讓簡單和高并發(fā)這兩個(gè)目標(biāo)兼得,我們需要 Project Loom 這個(gè)項(xiàng)目。

使用方法

在引入 Project Loom 之后,JDK 將引入一個(gè)新類:java.lang.Fiber。此類與 java.lang.Thread 一起,都成為了 java.lang.Strand 的子類。即線程變成了一個(gè)虛擬的概念,有兩種實(shí)現(xiàn)方法:Fiber 所表示的輕量線程和 Thread 所表示的傳統(tǒng)的重量級線程。

對于應(yīng)用開發(fā)人員,使用 Project Loom 很簡單:

  1. Fiber f = Fiber.schedule(() -> {  println("Hello 1");  lock.lock(); // 等待鎖不會掛起線程  try {      println("Hello 2");  } finally {      lock.unlock();  }  println("Hello 3");}) 

只需執(zhí)行 Fiber.schedule(Runnable task) 就能在 Fiber 中執(zhí)行任務(wù)。**最重要的是,上面例子中的 lock.lock() 操作將不再掛起底層線程。除了 Lock 不再掛起線程以外,像 Socket BIO 操作也不再掛起線程。** 但 synchronized,以及 Native 方法中線程掛起操作無法避免。

  1. synchronized (monitor) {  // 在 Fiber 中調(diào)用這條語句還是會掛起線程。  socket.getInputStream().read();} 

如上所示,F(xiàn)iber 的使用非常簡單。因此,讓現(xiàn)有系統(tǒng)使用 Project Loom 很容易。像 Tomcat、Jetty 這樣的 Web 容器,只需將處理請求操作從使用 ThreadPoolExecutor execute 或 submit 改為使用 Fiber schedule 即可。這個(gè)視頻 https://www.youtube.com/watch?v=vbGbXUjlRyQ&t=1240s 中的 Demo 展示了 Jetty 使用 Project Loom 改造之后并發(fā)吞吐能力的大幅提升。

實(shí)現(xiàn)原理

接下來簡單介紹一下 Project Loom 的實(shí)現(xiàn)原理。Project Loom 的使用主要基于 Fiber,而實(shí)現(xiàn)則主要基于 Continuation。Contiuation 表示一個(gè)可暫停和恢復(fù)的計(jì)算單元。在 Project Loom 中,Continuationn 使用 java.lang.Continuation 類實(shí)現(xiàn)。這個(gè)類主要供類庫實(shí)現(xiàn)使用,而不是直接被應(yīng)用開發(fā)人員使用。Continuation 主要內(nèi)容如下所示:

  1. package java.lang;public class Continuation implements Runnable {  public Continuation(ContinuationScope scope, Runnable target)    public final void run()    public static void yield(ContinuationScope scope)    public boolean isDone()} 

Continuation 實(shí)現(xiàn)了 Runnable 接口,構(gòu)造時(shí)除了需要提供一個(gè) Runnable 類型的參數(shù)以外,還需要提供一個(gè) java.lang.ContinuationScope 的參數(shù)。ContinuationScope 顧名思義表示 Continuation 的范圍。Continuation 可以被想象成是一個(gè)方法執(zhí)行過程,方法可以調(diào)用其它方法。同時(shí),方法執(zhí)行也有一定的影響范圍,如 try...catch 就規(guī)定了相應(yīng)的范圍。ContinuationScope 就起到了起到了相應(yīng)的作用。

Continuation 有兩個(gè)最重要的方法:run 和 yield。run 方法首次被調(diào)用時(shí),就會執(zhí)行 Runnable target 的 run 方法。但是,在調(diào)用了 yield 方法后,再次調(diào)用 run 方法,Continuation 就不會從頭執(zhí)行,而是從 yield 的位置開始執(zhí)行。

為了更形象的理解,下面看一個(gè)例子:

  1. Continuation con = new Continuation(SCOPE, () -> {  println("A");  Continuation.yield(SCOPE);  println("B");  Continuation.yield(SCOPE);  println("C");});con.run();con.run();con.run(); 

輸出結(jié)果:

  1. ABC 

上面的例子非常簡單:創(chuàng)建一個(gè) Continuation,其 Runnable target 打印 A、B、C,并在其中 yield 兩次。創(chuàng)建之后調(diào)用三次 run() 方法。如果這樣執(zhí)行一個(gè)普通的 Runnable,那應(yīng)該打印三次 A、B、C,一共打印九次。而 Continuation 在 yield 之后執(zhí)行 run,會從 yield 的位置往后執(zhí)行,而不是從頭開始。

Continuation yield 類似 Thread 的 yield,但前者需要顯式調(diào)用 run 方法恢復(fù)執(zhí)行。

在 Project Loom 之后,LockSupport 的 park 操作將變?yōu)椋?/p>

  1. public class LockSupport {  var strand = Strands.currentStrand();  if (strand instanceof Fiber) {    Continuation.yield(FIBER_SCOPE);  } else {    Unsafe.park(false, 0L);  }} 

七、展望

Java 作為使用率最高的編程軟件,在包括后端開發(fā)、手機(jī)應(yīng)用開發(fā)、大數(shù)據(jù)等眾多領(lǐng)域均有廣泛應(yīng)用。但畢竟是一門誕生20多年的編程語言,存在一些現(xiàn)在看來設(shè)計(jì)上的不足和受到后來者的挑戰(zhàn)都是正常。但必須說明,我們口中的 Java 并非一門單純的編程語言。而應(yīng)該被視為 Java 語言 + JVM + Java 類庫三部分組成。這三部分中,毫無疑問,JVM 是基礎(chǔ)。但 JVM 設(shè)計(jì)之初就并非和 Java 語言緊密綁定,緊密綁定的只是字節(jié)碼。由任何編程語言編譯得到的合法字節(jié)碼都能運(yùn)行在 JVM 之上。這使得 Java 語言層面設(shè)計(jì)的不足可有其它編程語言解決,于是出現(xiàn)了 Groovy、Scala、Kotlin、Clojure 等眾多 JVM 語言。這些語言很大程度上彌補(bǔ)了 Java 的不足。

但像多線程這樣的技術(shù),由于和底層虛機(jī)和操作系統(tǒng)有千絲萬縷的聯(lián)系,想要徹底改進(jìn),繞不開底層優(yōu)化。這就是 Project Loom 出現(xiàn)的原因。相信 Project Loom 技術(shù)會將 Java 的并發(fā)能力提升至和 Golang 一樣的水平,而付出的成本只是對現(xiàn)有項(xiàng)目的少量改動。

Azul 的 Deputy CTO Simon Ritter 曾透露 Project Loom 很可能在 Java 13 時(shí)發(fā)布。究竟能不能趕上 Java 13,這個(gè)不可知,好在 Java 13 的特性還未完全確定,說不定可以 Project Loom 可以趕上末班車。

就算 Project Loom 沒能和 Java 13 一起發(fā)布。但目前反應(yīng)式編程的趨勢也非常明顯。隨著新版本的 Spring 和 Kotlin 的發(fā)布,反應(yīng)式編程的使用、調(diào)試變得越來越簡單。Dubbo 也明確表示在 3.0 中將會支持 Project Reactor。R2DBC 在不久的未來也會支持 MySQL。因此,Java 異步編程將快速發(fā)展,在易用性方面迅速趕上甚至超過 Go。

另一方面,開發(fā)人員也不要將自己局限在某種特定技術(shù)上,對各種技術(shù)都保持開放的態(tài)度是開發(fā)人員技能不斷提高的前提。只會簡單說某某語言、某某技術(shù)比其它技術(shù)更好的技術(shù)人員永遠(yuǎn)不會成為出色的技術(shù)人員。

 

責(zé)任編輯:張燕妮 來源: 今日頭條
相關(guān)推薦

2025-02-06 16:51:30

2025-07-08 02:10:00

異步編程模式

2020-08-10 07:58:18

異步編程調(diào)用

2023-11-24 16:13:05

C++編程

2013-04-01 15:38:54

異步編程異步編程模型

2020-09-24 08:45:10

React架構(gòu)源碼

2025-02-24 00:10:00

2017-03-13 09:19:38

CAP編程語言

2022-06-16 13:08:30

Combine響應(yīng)式編程訂閱

2021-12-12 18:15:06

Python并發(fā)編程

2013-04-01 15:25:41

異步編程異步EMP

2021-03-22 08:45:30

異步編程Java

2020-10-15 13:29:57

javascript

2025-05-23 09:14:53

2021-08-02 11:13:28

人工智能機(jī)器學(xué)習(xí)技術(shù)

2022-03-31 07:52:01

Java多線程并發(fā)

2025-04-21 04:00:00

2011-02-22 08:49:16

.NET同步異步

2011-02-22 09:09:21

.NETAsync CTP異步
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

蜜臀久久精品| 久草视频手机在线观看| 三级成人黄色影院| 欧美国产欧美亚州国产日韩mv天天看完整| 国产精品第一第二| 精品人妻伦九区久久aaa片| 粉嫩av一区二区| 91久久香蕉国产日韩欧美9色| 亚洲午夜激情| 亚洲人妻一区二区| 久久精品久久99精品久久| 欧美激情亚洲综合一区| 日本人亚洲人jjzzjjz| 超碰成人在线免费| 欧美三级蜜桃2在线观看| 日韩黄色片在线| 北岛玲日韩精品一区二区三区| 国产suv精品一区二区三区| 国产精品久久久久久五月尺| 毛片aaaaa| 日韩伦理视频| 精品夜色国产国偷在线| 欧美一级大片免费看| 欧美三区四区| 天天亚洲美女在线视频| 国内外成人激情免费视频| 欧美性孕妇孕交| 国产成人av电影免费在线观看| 国产精品r级在线| 国产在线成人精品午夜| 91精品电影| 亚洲视频axxx| 精品人妻一区二区三区香蕉 | 亚洲丝袜啪啪| 欧美sm美女调教| 欧美一级特黄aaa| 亚洲精品国产嫩草在线观看| 午夜精品一区在线观看| 2022中文字幕| 在线āv视频| 日韩理论片一区二区| 日韩中文字幕一区| 欧美新色视频| 国产日韩欧美精品综合| 久久久久综合一区二区三区| 五月婷婷六月色| 成人av网站在线观看免费| 91av一区二区三区| 精品国自产在线观看| 波多野结衣在线电影| 日韩经典一区| 色香蕉成人二区免费| 日本毛片在线免费观看| 黄色在线观看www| 亚洲国产精品久久不卡毛片| 久久艹国产精品| 77thz桃花论族在线观看| 亚洲尤物在线视频观看| 亚洲中文字幕无码一区二区三区| 久草中文在线| 亚洲精品国产高清久久伦理二区 | 中文字幕人成人乱码| 日韩中文字幕不卡视频| 国产精品免费在线视频| 999国产精品永久免费视频app| 日韩色av导航| 日本aⅴ在线观看| 欧美午夜视频| 4438全国成人免费| 日本免费精品视频| 久久福利视频一区二区| 亚洲va男人天堂| 蜜臀av中文字幕| 91一区一区三区| 日本在线观看一区二区| 日韩av中文| 亚洲精品久久久蜜桃| 欧美狂野激情性xxxx在线观| 日本性爱视频在线观看| 婷婷开心激情综合| 欧美成人黄色网址| 久久av偷拍| 国产福利91精品一区二区| 国产欧美一区二区三区鸳鸯浴| 日韩福利视频| 成人福利网站| 午夜电影一区二区三区| 久久久久国产精品熟女影院| 日韩免费在线电影| 日韩精品影音先锋| 熟女俱乐部一区二区| 久久久影院免费| 欧美国产日韩精品| 国产成人a v| 国产成人av电影在线观看| 欧美激情第六页| 黄色在线论坛| 欧美性猛交xxxx免费看| 亚洲综合20p| 亚洲宅男网av| 免费av一区二区| 日韩熟女一区二区| 国产激情精品久久久第一区二区| 久久精品日韩| 91福利国产在线观看菠萝蜜| 色偷偷88欧美精品久久久| 国产精品igao网网址不卡| 欧美交a欧美精品喷水| www.亚洲人.com| www.国产高清| 国产激情一区二区三区| 午夜精品区一区二区三| 金瓶狂野欧美性猛交xxxx | 欧美 国产 日本| 粉嫩一区二区三区在线观看| 亚洲男人av在线| 久青草视频在线观看| 日本在线不卡视频| 久久青青草综合| 女同视频在线观看| 欧美日韩精品一区二区三区| 日本japanese极品少妇| 欧美日韩1080p| 91热福利电影| 自拍视频在线| 色狠狠色狠狠综合| 熟女人妻在线视频| 好吊视频一二三区| 久久国产精品99国产| 99re视频| 国产成人l区| 欧美三级在线看| 91精品人妻一区二区| 尤物精品在线| αv一区二区三区| av片哪里在线观看| 制服丝袜成人动漫| 欧美色视频一区二区三区在线观看| 久久激情久久| 欧美日韩精品一区| 粉嫩一区二区| 亚洲女人被黑人巨大进入al| 国产又大又黄视频| 99亚偷拍自图区亚洲| 福利视频免费在线观看| 在线精品视频一区| 欧美高清视频一区二区| 国产aⅴ一区二区三区| 1区2区3区欧美| 三日本三级少妇三级99| 婷婷综合在线| 亚洲free性xxxx护士白浆| 黄色动漫在线观看| 欧美一二区视频| 欧美精品一级片| 成人小视频免费观看| 国产真人做爰毛片视频直播| 国产欧美自拍一区| 久久频这里精品99香蕉| 无码国精品一区二区免费蜜桃| 精品国产福利在线| 中文字幕在线观看网址| 老司机午夜免费精品视频| 视频一区二区三区免费观看| 国产精品久久久久久吹潮| www.欧美精品| www.久久色| 午夜精品久久一牛影视| 亚洲成人精品电影在线观看| 欧美成人三级伦在线观看| 国产精品国产一区| 亚洲综合国产精品| 9765激情中文在线| 亚洲欧美在线免费观看| 在线观看国产精品入口男同| 亚洲免费资源在线播放| 人妻换人妻a片爽麻豆| 国产日韩欧美一区| 色99中文字幕| 麻豆精品久久| 777午夜精品福利在线观看| 色吊丝在线永久观看最新版本| 在线视频综合导航| 亚洲最大的黄色网址| 不卡av在线免费观看| 天天碰免费视频| 五月精品视频| 国产伦理一区二区三区| 亚洲www免费| 欧美成人在线网站| 免费在线国产| 欧美一区二区三区在| 欧美日韩综合在线观看| 国产精品国产三级国产aⅴ入口| 亚洲国产欧美日韩在线| 久久天堂成人| 中文字幕第50页| 美女少妇全过程你懂的久久 | 免费人成自慰网站| 国产精品嫩模av在线| 91美女片黄在线观看游戏| 日本在线影院| 久久亚洲精品视频| 加勒比一区二区三区在线| 欧美一级高清片在线观看| 国产又大又粗又爽| 一区二区三区在线免费观看| 中字幕一区二区三区乱码| 国产成人鲁色资源国产91色综| www黄色在线| 一区二区国产在线观看| 一区二区三区一级片| 免费一区二区三区视频导航| 国产不卡一区二区在线观看| 丁香婷婷久久| 日韩av电影在线网| 第四色日韩影片| 美女福利视频一区| 成年人视频在线看| 亚洲精品天天看| 神宫寺奈绪一区二区三区| 555www色欧美视频| 天天天天天天天干| 日韩欧美亚洲成人| 亚洲一区欧美在线| 亚洲一二三四区| 青青草免费av| 综合久久综合久久| 中文天堂资源在线| 久久精品夜色噜噜亚洲a∨| av在线播放网址| 丰满白嫩尤物一区二区| 国产精品久久久久久久99| 三级欧美韩日大片在线看| av之家在线观看| 日韩天天综合| 很污的网站在线观看| 黑人一区二区| 黄色一级片国产| 亚洲91精品| 正义之心1992免费观看全集完整版| 国产探花在线精品| 蜜桃成人在线| 国产一区二区三区四区大秀| 日本电影一区二区三区| 亚洲精品蜜桃乱晃| 欧美精彩一区二区三区| 亚洲+变态+欧美+另类+精品| 狠狠干一区二区| 欧美激情影院| 欧美视频1区| 黑丝美女一区二区| 视频一区二区三区免费观看| 成人羞羞网站入口| 中文字幕一区二区三区精彩视频| 国产国产精品| 久久视频免费在线| 好吊一区二区三区| 欧美成人免费在线观看视频| 欧美资源在线| 九一精品在线观看| 精品一区二区在线视频| 亚洲一区二区图片| 成人美女视频在线看| 丰满少妇一区二区三区| 久久久精品一品道一区| 免费看的黄色录像| 最新不卡av在线| 国产亚洲成人精品| 欧美日韩视频在线| 欧美人一级淫片a免费播放| 欧美三日本三级三级在线播放| 国产美女裸体无遮挡免费视频| 日韩西西人体444www| 人妻一区二区三区免费| 日韩国产精品一区| 91在线免费看| 欧美激情手机在线视频| 国产美女高潮在线| 国产精品久久久久av免费| 精品中文在线| 免费日韩av电影| 久久精品免费一区二区三区| 国产va亚洲va在线va| 视频在线观看一区二区三区| 国产性生活一级片| 91美女福利视频| 中日韩一级黄色片| 精品人伦一区二区三区蜜桃网站| 国产男人搡女人免费视频| 欧美成人一区二区三区| 蝌蚪视频在线播放| 蜜臀久久99精品久久久无需会员| 69久成人做爰电影| 国产精品久久久久久中文字 | 欧美日韩高清免费| 91成人网在线观看| 午夜精品久久久内射近拍高清| 激情五月激情综合网| 熟女丰满老熟女熟妇| 日韩美女视频一区二区| 69国产精品视频免费观看| 在线播放日韩导航| 欧美日韩在线精品一区二区三区激情综 | 欧洲美女免费图片一区| 白嫩亚洲一区二区三区| 欧洲久久久久久| 欧美涩涩视频| 中文字幕在线观看日| 91麻豆swag| 美女的奶胸大爽爽大片| 欧美午夜精品免费| 日韩精品系列| 欧美国产日韩二区| 日韩成人综合网站| 欧美在线日韩精品| 国产亚洲综合精品| 国产在线a视频| 国产精品久久久久久久蜜臀| 9i精品福利一区二区三区| 欧美xxxx老人做受| av中文字幕在线观看| 国产精品视频免费在线观看| 西瓜成人精品人成网站| 免费视频爱爱太爽了| 国产寡妇亲子伦一区二区| 美女av免费看| 欧美写真视频网站| 欧美白人做受xxxx视频| 69av成年福利视频| 极品一区美女高清| 国产精品久久久久久久乖乖| 国产中文字幕精品| www深夜成人a√在线| 欧美三级日韩三级国产三级| 成人全视频高清免费观看| 日本高清+成人网在线观看| 少妇精品导航| 国产女大学生av| av在线不卡免费看| 日韩av在线播放观看| 精品久久人人做人人爱| 少女频道在线观看免费播放电视剧| 91精品视频在线播放| 一级欧洲+日本+国产 | 黄色在线视频网址| 国产视频亚洲视频| 中国字幕a在线看韩国电影| 精选一区二区三区四区五区| 国产亚洲一区在线| 国产aⅴ激情无码久久久无码| 色综合欧美在线| 成人在线二区| 国产欧美精品一区二区三区-老狼 国产欧美精品一区二区三区介绍 国产欧美精品一区二区 | 自拍欧美一区| 热久久精品免费视频| 欧美激情一区二区三区蜜桃视频| 中文字幕码精品视频网站| 日韩亚洲在线观看| 精品视频一区二区三区| 成人av在线播放观看| 成人动漫一区二区| caoporn国产| 在线视频免费一区二区| 成人免费观看49www在线观看| 大桥未久一区二区三区| 成人激情黄色小说| 国产91精品一区| 色av吧综合网| 亚洲精品aⅴ| 国产视频一视频二| 国产色产综合产在线视频| 91尤物国产福利在线观看| 欧美精品在线视频观看| 理论片一区二区在线| 久久久久免费精品| 亚洲欧美日韩中文播放| 色欲久久久天天天综合网| 日韩免费在线免费观看| 五月久久久综合一区二区小说| 国产精品成人99一区无码| 一本到不卡精品视频在线观看| 日本综合在线| 精品国产综合| 久热成人在线视频| 日本一区二区不卡在线| 一区二区三欧美| 欧美视频二区欧美影视| 久久美女福利视频| 中文字幕在线观看一区二区| 日本久久一级片| 国产欧美精品久久久| 99精品国产99久久久久久福利| 青娱乐国产视频| 精品国产91乱码一区二区三区| 欧洲一级精品| www.日本少妇| 综合婷婷亚洲小说| 免费在线观看一级毛片| 成人av播放|