成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java 異步編程:從 Future 到 Loom

新聞 前端
眾所周知,Java 開始方法執(zhí)行到結束,都是由同一個線程完成的。這種方式雖易于開發(fā)調試,但容易因為鎖、IO 等原因導致線程掛起,產生線程上下文切換。

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

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

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

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

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

一、Future

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

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

但這個解決方案有很多缺陷:

  1. 無法方便得知任務何時完成
  2. 無法方便獲得任務結果
  3. 在主線程獲得任務結果會導致主線程阻塞

二、Callback

為了解決使用 Future 所存在的問題,人們提出了一個叫 Callback 的解決方案。比如 Google Guava 包中的 ListenableFuture 就是基于此實現(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)建異步任務。通過 Futures.addCallback(explosion, new FutureCallback<Explosion>() {} 添加處理結果的回調函數(shù)。這樣避免獲取并處理異步任務執(zhí)行結果阻塞調起線程的問題。Callback 是將任務執(zhí)行結果作為接口的入參,在任務完成時回調 Callback 接口,執(zhí)行后續(xù)任務,從而解決純 Future 方案無法方便獲得任務執(zhí)行結果的問題。

但 Callback 產生了新的問題,那就是代碼可讀性的問題。因為使用 Callback 之后,代碼的字面形式和其所表達的業(yè)務含義不匹配,即業(yè)務的先后關系到了代碼層面變成了包含和被包含的關系。

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

Callback Hell 問題可以從兩個方向進行一定的解決:一是事件驅動機制、二是鏈式調用。前者被如 Vert.x 所使用,后者被 CompletableFuture、反應式編程等技術采用。但這些優(yōu)化的效果有限,不能根本上解決 Callback 機制所帶來的代碼可維護性的下降。

Callback 與 NIO

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

下面看一個真實的例子。這個例子背后的完整應用的功能是將微軟 Exchange 服務接口(Exchange Web Service)轉換為 Rest 風格的接口,下面這段代碼是這個應用的一部分。

  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 中,我們已經能看到嵌套兩層的 Callback。而上面實例中的 EwsCalendarHandler 所實現(xiàn)的 ChannelInboundHandler 接口,本質上也是一個回調接口。

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

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

三、Servlet 3.0

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

▼ 示例: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 應用中,接受請求和返回響應必須在同一個線程的問題,實現(xiàn)了如下目標:

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

除了直接使用 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 的技術局限

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

四、反應式編程

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

▼ 圖:反應式編程的特性 ▼

Java 異步編程:從 Future 到 Loom

▼ 反應式編程簡單示例 ▼

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

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

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

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

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

  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}"                      }              }      }} 

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

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

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

反應式編程的應用范圍

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

五、Kotlin 協(xié)程

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

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

使用 Kotlin 協(xié)程之后最大的好處是異步代碼的可讀性大大提高。如果上一個示例用 Kotlin 協(xié)程實現(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 應用中使用 Kotlin 協(xié)程還有些小繁瑣,但在 Spring Boot 2.2 中,可以直接在 Spring WebFlux 方法上使用 suspend 關鍵字。

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

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

Kotlin 協(xié)程的局限性

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

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

六、Project Loom

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

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

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

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

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

Java 異步編程:從 Future 到 Loom

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

使用方法

在引入 Project Loom 之后,JDK 將引入一個新類:java.lang.Fiber。此類與 java.lang.Thread 一起,都成為了 java.lang.Strand 的子類。即線程變成了一個虛擬的概念,有兩種實現(xiàn)方法:Fiber 所表示的輕量線程和 Thread 所表示的傳統(tǒ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í)行任務。**最重要的是,上面例子中的 lock.lock() 操作將不再掛起底層線程。除了 Lock 不再掛起線程以外,像 Socket BIO 操作也不再掛起線程。** 但 synchronized,以及 Native 方法中線程掛起操作無法避免。

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

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

實現(xiàn)原理

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

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

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

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

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

輸出結果:

  1. ABC 

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

Continuation yield 類似 Thread 的 yield,但前者需要顯式調用 run 方法恢復執(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ā)、手機應用開發(fā)、大數(shù)據等眾多領域均有廣泛應用。但畢竟是一門誕生20多年的編程語言,存在一些現(xiàn)在看來設計上的不足和受到后來者的挑戰(zhàn)都是正常。但必須說明,我們口中的 Java 并非一門單純的編程語言。而應該被視為 Java 語言 + JVM + Java 類庫三部分組成。這三部分中,毫無疑問,JVM 是基礎。但 JVM 設計之初就并非和 Java 語言緊密綁定,緊密綁定的只是字節(jié)碼。由任何編程語言編譯得到的合法字節(jié)碼都能運行在 JVM 之上。這使得 Java 語言層面設計的不足可有其它編程語言解決,于是出現(xiàn)了 Groovy、Scala、Kotlin、Clojure 等眾多 JVM 語言。這些語言很大程度上彌補了 Java 的不足。

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

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

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

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

 

責任編輯:張燕妮 來源: 今日頭條
相關推薦

2025-02-06 16:51:30

2020-08-10 07:58:18

異步編程調用

2023-11-24 16:13:05

C++編程

2013-04-01 15:38:54

異步編程異步編程模型

2020-09-24 08:45:10

React架構源碼

2025-02-24 00:10:00

2021-12-12 18:15:06

Python并發(fā)編程

2017-03-13 09:19:38

CAP編程語言

2022-06-16 13:08:30

Combine響應式編程訂閱

2022-03-31 07:52:01

Java多線程并發(fā)

2021-03-22 08:45:30

異步編程Java

2013-04-01 15:25:41

異步編程異步EMP

2020-10-15 13:29:57

javascript

2021-08-02 11:13:28

人工智能機器學習技術

2025-04-21 04:00:00

2025-05-23 09:14:53

2011-02-22 08:49:16

.NET同步異步

2011-02-22 09:09:21

.NETAsync CTP異步

2020-12-07 09:40:19

Future&Futu編程Java

2024-12-23 08:00:45

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 99综合网| 欧美亚洲综合久久 | 日韩一区二区三区在线视频 | 欧美日韩在线观看视频网站 | 精品综合 | 五月精品视频 | 婷婷在线视频 | 婷婷激情五月网 | 国产成人精品一区二 | 91麻豆精品国产91久久久更新资源速度超快 | av网站推荐 | 日本欧美国产在线 | 久久三级av | 欧美aⅴ片| 日韩精品极品视频在线观看免费 | 一区二区三区高清不卡 | 欧美国产亚洲一区二区 | 日本电影网站 | 亚洲日韩中文字幕一区 | 91精品国产92 | 天堂综合网 | 中文天堂在线一区 | 久久午夜剧场 | 福利视频网 | 欧美色性| 日本久久视频 | 亚洲精品久久久蜜桃网站 | 亚洲一区视频在线 | 中文字幕在线观看av | 亚洲午夜av | 二区久久 | 视频一二三区 | 国产精品99视频 | 欧美一区二区三区在线观看视频 | 伊人网综合 | 91色视频在线观看 | 四虎最新 | 中国黄色毛片视频 | 欧美日韩亚洲国产综合 | 午夜不卡一区二区 | 美女在线观看av |