精品欧美一区二区三区在线观看 _久久久久国色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ù)棧公眾號

欧美国产日韩xxxxx| 欧美美女喷水视频| 麻豆亚洲一区| 亚洲视频在线观看一区二区 | 精品一区二区国语对白| 欧美多人乱p欧美4p久久| 亚洲天堂成人av| 日韩综合av| 激情成人中文字幕| 日韩最新中文字幕| 亚洲欧美综合在线观看| 久草热8精品视频在线观看| 欧美精品18videos性欧| 97在线观看免费视频| a级日韩大片| 欧美日韩国产中文| www.日本在线播放| 老司机av在线免费看| 99re视频精品| 1卡2卡3卡精品视频| 日韩精品1区2区| 综合久久99| 一区二区欧美亚洲| 日批在线观看视频| 国产麻豆一区二区三区| 色猫猫国产区一区二在线视频| 在线观看17c| 2021av在线| 91在线国产福利| 99re在线观看| 亚洲天堂2021av| 美日韩精品视频| 国外成人性视频| 日本美女黄色一级片| 国产成人一区| 亚洲电影免费观看| 三级网站免费看| 亚洲网站免费| 欧美三片在线视频观看| 国产男女激情视频| 欧美电影免费观看| 欧美日韩免费看| 精品视频在线观看一区| 三级网站视频在在线播放| 中文字幕一区二区三区四区| 秋霞在线观看一区二区三区| 三级在线观看| 26uuu精品一区二区三区四区在线 26uuu精品一区二区在线观看 | 奇米一区二区三区av| 欧美亚洲另类激情另类| 日韩乱码一区二区| 在线看片成人| 久久久久久久一区二区| 国产一级视频在线观看| 欧美日韩ab| 久久91精品国产| 欧美日韩精品一区二区三区视频播放| 国产精品成人一区二区不卡| 视频直播国产精品| 亚洲一级理论片| 91久久久精品国产| 美女性感视频久久久| 国产高潮国产高潮久久久91| 你懂的国产精品永久在线| 欧美成人在线免费| 国产亚洲精品久久777777| 欧美日韩中文| 国内精品400部情侣激情| 久久精品性爱视频| av成人毛片| 欧美在线中文字幕| 无码人妻丰满熟妇精品| 美美哒免费高清在线观看视频一区二区 | 日韩欧美激情一区| 亚洲乱妇老熟女爽到高潮的片 | 青青草精品在线视频| 午夜欧美视频| 久久免费视频在线观看| 亚洲午夜18毛片在线看| 丝袜美腿亚洲色图| 成人黄色中文字幕| 国产黄色av片| 久久综合久色欧美综合狠狠| 亚洲一区二区自拍偷拍| 天堂av在线电影| 精品日韩中文字幕| 天天碰免费视频| 疯狂欧洲av久久成人av电影 | 亚洲精品乱码久久久久久9色| avtt综合网| 亚洲视频综合网| 天海翼在线视频| 日韩亚洲精品在线| 国产精品久在线观看| 国产a级免费视频| 91亚洲国产成人精品一区二三| 日韩妆和欧美的一区二区| 国产三区在线观看| 粉嫩av一区二区三区免费野| 色婷婷成人在线| 成人性生交大片免费看中文视频| 国产午夜精品视频| 青娱乐国产在线视频| 蜜桃视频一区| 国产精品免费在线播放| www日韩tube| 午夜精品福利在线| 国产色视频在线播放| 国产三级精品三级在线观看国产| 最近2019年手机中文字幕 | 天堂8中文在线| 在线视频一区二区三| 香蕉视频在线观看黄| 国产影视精品一区二区三区| 欧美精品在线视频观看| 国产一级片免费在线观看| 成人免费毛片app| 国产精品99久久久久久大便| 中文字幕 在线观看| 日韩欧美精品在线视频| 国产精品一区二区亚洲| 鲁大师成人一区二区三区| 成人在线资源网址| 欧美jizz18hd性欧美| 日本精品一级二级| 欧类av怡春院| 黄色免费成人| 亚洲自拍av在线| 拍真实国产伦偷精品| 色8久久人人97超碰香蕉987| 男男做爰猛烈叫床爽爽小说| 欧美日韩一区二区国产| 亚洲在线第一页| 高清免费电影在线观看| 欧美日韩三级一区| 人妻精品久久久久中文| 美女尤物久久精品| 欧美系列一区| 爱情电影社保片一区| 欧美精品一区二区不卡| 精品视频在线观看免费| 国产成人午夜精品影院观看视频| 无码人妻精品一区二区三区99v| 国产精品蜜月aⅴ在线| 一区二区三区四区视频| 黄色一级视频免费看| 久久久夜色精品亚洲| 水蜜桃色314在线观看| 红杏aⅴ成人免费视频| 久久久久国色av免费观看性色| 99国产在线播放| 亚洲免费av网站| 国产成人精品综合久久久久99| 综合天天久久| 99在线国产| 黑人另类精品××××性爽| 精品国偷自产国产一区| 日韩精品在线不卡| 91麻豆精东视频| 黄色片在线免费| 成人亚洲一区| 91精品啪aⅴ在线观看国产| 菠萝蜜视频国产在线播放| 日韩三级电影网址| 日本熟妇一区二区| 久久综合九色综合97婷婷女人 | 中文网丁香综合网| 激情不卡一区二区三区视频在线| 久久99久久99精品免观看粉嫩| 高清一区二区三区四区| 精品成人在线视频| 国产高清一区二区三区四区| 美女国产一区二区三区| 亚洲精品少妇一区二区| 国产区精品视频在线观看豆花| 欧美一级淫片播放口| 国模精品一区二区| 欧美日韩二区三区| 国产一二三四在线| 久久精品夜色噜噜亚洲a∨| www.久久久精品| 欧美激情在线| 另类小说综合网| 久久精品xxxxx| 欧美黑人一级爽快片淫片高清| 日本电影一区二区在线观看 | 成人小说亚洲一区二区三区 | 国产精品视频在线观看免费 | 日韩亚洲欧美成人| 亚洲av色香蕉一区二区三区| 狠狠色狠狠色综合日日五| 国产第一页精品| 成人免费av网站| 色综合天天色综合| 国产精品jizz在线观看美国| 日本欧洲国产一区二区| 欧美久久一区二区三区| 欧美一级大胆视频| 久久精品视频观看| 精品一区二区三区四区| 99久久亚洲精品日本无码| 欧美日韩精品在线| 三级av在线免费观看| 久久精品一区蜜桃臀影院| 亚洲精品成人无码毛片| 麻豆国产91在线播放| 91国视频在线| 一区二区影视| 视频在线99| 欧美调教在线| y111111国产精品久久婷婷| av免费在线一区| 97欧美精品一区二区三区| 黄色网页网址在线免费| 亚洲人精选亚洲人成在线| 亚洲美女性生活| 欧美日韩视频不卡| 九九精品免费视频| 亚洲国产毛片aaaaa无费看| 日韩亚洲欧美中文字幕| 久久精品视频一区二区三区| 精品人妻伦一二三区久| 国产一区二区三区免费| 午夜激情av在线| 另类av一区二区| 国产亚洲综合视频| 亚洲第一毛片| 国产黄色激情视频| 亚洲欧美一区在线| 天天做天天爱天天高潮| 日韩精品免费一区二区在线观看| 欧美成人蜜桃| 久久综合五月婷婷| 国产精品一区二区三区在线| 欧美成年网站| 亚洲精品免费在线视频| 二区三区精品| 亚洲自拍偷拍网址| 久久久久久亚洲精品美女| 91九色在线视频| 疯狂欧洲av久久成人av电影 | 国产免费黄色大片| 69堂亚洲精品首页| 在线观看国产精品视频| 欧美无乱码久久久免费午夜一区| 亚洲精品久久久久久久蜜桃| 色婷婷国产精品| 欧美brazzers| 欧美日韩在线直播| 一级黄色片在线| 欧美精品在线观看一区二区| 一区二区日韩在线观看| 91精品国产欧美一区二区| 国产精品爽爽久久| 日韩欧美一级特黄在线播放| 亚洲第一视频在线| 亚洲第一精品夜夜躁人人躁| 天堂在线视频网站| 国产视频精品久久久| 美丽的姑娘在线观看免费动漫| 亚洲免费影视第一页| 国产三级在线看| 深夜福利亚洲导航| 成人福利在线观看视频| 欧美高跟鞋交xxxxxhd| 国产福利电影在线播放| 91av在线免费观看| 国产亚洲一区二区手机在线观看| 国产精品久久网| 视频一区日韩| 久久久久久a亚洲欧洲aⅴ| jizzjizz欧美69巨大| 日本女人高潮视频| 亚洲国产99| www.色就是色| 豆国产96在线|亚洲| 五级黄高潮片90分钟视频| 国产精品免费网站在线观看| 精品欧美一区二区久久久久| 午夜免费久久看| 糖心vlog精品一区二区| 日韩一区二区三区免费看| 天天干天天爱天天操| 亚洲最新av在线网站| 手机av免费在线| 欧洲午夜精品久久久| 91麻豆精品| 精品久久一区二区三区蜜桃| 成人vr资源| 免费一级特黄毛片| 日本欧美久久久久免费播放网| 99国产精品免费视频| 久久女同精品一区二区| 中文字幕在线2021| 午夜欧美大尺度福利影院在线看 | 精品国产凹凸成av人导航| 黄色在线网站| 欧美黄色三级网站| 成人免费一区| 精品一区久久久久久| 天天做天天爱天天综合网| 欧美 日韩 国产一区| 国产九色精品成人porny| 91国模少妇一区二区三区| 一区二区三区在线播| 综合久久中文字幕| 日韩成人av在线| 日本理论片午伦夜理片在线观看| 国产成人精品免高潮费视频| jizzjizzjizz欧美| 中文精品一区二区三区| 丝袜诱惑亚洲看片| 欧美精品欧美极品欧美激情| 亚洲精品乱码久久久久久久久| 欧美特级黄色片| 国产视频久久久久| 成人三级小说| 亚洲一区二区在线播放| 欧洲乱码伦视频免费| 97av视频在线观看| 成人一区二区在线观看| 久草福利资源在线观看| 91精品国产手机| 香蕉视频在线免费看| 国产精品pans私拍| 亚洲精品国产动漫| 男女超爽视频免费播放| 成人性生交大片免费看视频在线| 欧美三级黄色大片| 欧美麻豆精品久久久久久| 都市激情在线视频| 国产福利精品av综合导导航| 清纯唯美亚洲经典中文字幕| 日日摸日日碰夜夜爽无码| 床上的激情91.| 国产亚洲成人av| 精品第一国产综合精品aⅴ| 在线中文字幕第一页| 亚洲伊人一本大道中文字幕| 亚洲成人一区| 国产精品嫩草影院8vv8| 一区二区中文字幕在线| 人妻中文字幕一区二区三区| 一区二区三区美女xx视频| 99久久er| 黄色高清视频网站| 精品一区二区三区免费播放| 爱爱视频免费在线观看| 91精品一区二区三区久久久久久| 国产区在线看| 成人av男人的天堂| 国产在线欧美| 日韩aaaaa| 欧美在线不卡视频| av电影在线观看一区二区三区| 国产精品视频网址| 五月激情综合| 欧美一区二区三区影院| 亚洲成年人影院| 青青青手机在线视频观看| 国产99在线|中文| 久久精品国产亚洲夜色av网站| 亚洲欧美天堂在线| 一区二区三区欧美| 水中色av综合| 国产精品久久中文| 欧美精品入口| 国产精品无码网站| 在线看国产一区| av在线下载| 精品欧美日韩| 久久精品国产色蜜蜜麻豆| 国产女人被狂躁到高潮小说| 亚洲国产欧美一区二区三区久久| **欧美日韩在线观看| 亚洲精品成人悠悠色影视| 中文字幕av片| 不卡av电影院| 东京久久高清| aaa毛片在线观看| 18欧美亚洲精品| 婷婷伊人综合中文字幕| 国产精品日韩欧美大师| 精品二区视频| 国产黄色录像视频| 日韩美女天天操| 日韩不卡免费高清视频| 2022中文字幕| 久久综合久久鬼色中文字| 国产美女明星三级做爰| 91国产一区在线| 久久精品影视| 国精产品一区一区三区免费视频 | 午夜视频在线免费播放| 国产精品久久久久久久7电影| 欧美日韩国产探花| 亚洲最大成人综合网| 亚洲丁香婷深爱综合| 亚洲一区有码| 91av在线免费播放|