欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入淺析Java 虛擬線程

 更新時(shí)間:2025年02月08日 09:12:10   作者:曾彪彪  
Java21引入了虛擬線程,這是一種輕量級(jí)線程,適用于IO密集型的應(yīng)用,可以極大提高應(yīng)用的性能和吞吐量,虛擬線程是由傳統(tǒng)線程執(zhí)行的,由JVM控制上下文切換,創(chuàng)建和銷毀的開銷小,適用于高并發(fā)場(chǎng)景,本文介紹Java 虛擬線程的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧

在Java 21中,引入了虛擬線程,這是一個(gè)非常非常重要的特性,之前一直苦苦尋找的Java協(xié)程,終于問(wèn)世了。在高并發(fā)以及IO密集型的應(yīng)用中,虛擬線程能極大的提高應(yīng)用的性能和吞吐量。

什么是虛擬線程

先來(lái)看一下虛擬線程的概念。

虛擬線程概念

DK 21 引入了虛擬線程的支持,這是為了改善 Java 應(yīng)用程序在高并發(fā)場(chǎng)景下的性能。虛擬線程是一種輕量級(jí)線程,具有較小的內(nèi)存占用,能夠更高效地進(jìn)行上下文切換,適用于 I/O 密集型的應(yīng)用程序。

虛擬線程的工作原理

當(dāng)應(yīng)用程序啟動(dòng)一個(gè)虛擬線程時(shí),JVM會(huì)將這個(gè)虛擬線程交給JVM底層的線程池去執(zhí)行,這個(gè)底層的線程池是一個(gè)傳統(tǒng)線程池,并且真正執(zhí)行虛擬線程中任務(wù)的線程,也是傳統(tǒng)線程(操作系統(tǒng)線程)。當(dāng)虛擬線程遇到阻塞時(shí),JVM會(huì)立刻將虛擬線程掛起,讓其它虛擬線程執(zhí)行。也就是說(shuō),開啟一個(gè)虛擬線程,并不需要啟用一個(gè)傳統(tǒng)線程,一般一個(gè)傳統(tǒng)線程,可以執(zhí)行多個(gè)虛擬線程的任務(wù)。在執(zhí)行過(guò)程中,可以把虛擬線程理解成任務(wù)task。

這里舉一個(gè)列子,假設(shè)用戶創(chuàng)建了1000個(gè)虛擬線程,JVM的執(zhí)行虛擬線程的線程池線程數(shù)是10,那么當(dāng)?shù)谝粋€(gè)虛擬線程V1需要執(zhí)行時(shí),JVM會(huì)將V1調(diào)度到傳統(tǒng)線程T1上,以此類推,虛擬線程V2會(huì)被調(diào)度到傳統(tǒng)線程T2上,那么V3->T3,V4->T4,… V10->T10。當(dāng)執(zhí)行到V11時(shí),這里有三種情況:

  • 如果V1~V10中有任何一個(gè)線程遇到阻塞,我們這里假設(shè)V3遇到阻塞,那么JVM會(huì)將V3掛起,此時(shí)T3線程可用,那么V11被T3執(zhí)行。

  • 如果V1~V10沒(méi)有線程被阻塞,那么JVM根據(jù)劃分的時(shí)間片,假設(shè)每個(gè)虛擬線程允許執(zhí)行100ns,那么過(guò)了100ns后,這里V1最新執(zhí)行,JVM則將V1掛起,讓T1去執(zhí)行V11。

  • 如果以上兩種情況都不滿足,那么先將V11掛起,等待有可用的傳統(tǒng)線程時(shí),再執(zhí)行V11。

對(duì)于被阻塞的線程,如V3,當(dāng)IO結(jié)束后,操作系統(tǒng)會(huì)通過(guò)事件,如epoll通知JVM,V3的IO操作已結(jié)束,此時(shí)JVM重新喚醒V3,選擇可用的傳統(tǒng)線程,來(lái)執(zhí)行V3的任務(wù)。

這里需要注意兩點(diǎn):

  • 虛擬線程IO執(zhí)行完成后,會(huì)通過(guò)操作系統(tǒng)的事件通知機(jī)制,如epoll來(lái)通知JVM。這一點(diǎn)對(duì)于虛擬線程的高效調(diào)度至關(guān)重要,因?yàn)樗_保了 阻塞的 I/O 操作 不會(huì)占用操作系統(tǒng)線程的時(shí)間片,避免了傳統(tǒng)線程池的高資源消耗和效率低下。。

  • JVM在對(duì)虛擬線程進(jìn)行上下文切換時(shí),因?yàn)椴簧婕暗讲僮飨到y(tǒng)級(jí)別的線程上下文切換,代價(jià)非常低,速度也非???。

虛擬線程的調(diào)度

一般來(lái)說(shuō),程序員不需要對(duì)虛擬線程的調(diào)度進(jìn)行管理,在JDK 21中,JVM默認(rèn)啟用了虛擬線程,并且會(huì)使用默認(rèn)的ForkJoinPool線程池來(lái)執(zhí)行虛擬線程,并且線程池的大小,也會(huì)根據(jù)虛擬線程的數(shù)量,進(jìn)行動(dòng)態(tài)調(diào)整。如果需要手動(dòng)管理執(zhí)行虛擬線程的線程池大小,那么需要自定義線程池,并將虛擬線程交給自定義的線程池來(lái)執(zhí)行,這樣雖然可行,通常沒(méi)有必要。

虛擬線程與傳統(tǒng)線程區(qū)別

虛擬線程與傳統(tǒng)線程的區(qū)別主要在于:

  • 創(chuàng)建虛擬線程時(shí),JVM不會(huì)創(chuàng)建一個(gè)操作系統(tǒng)線程,創(chuàng)建一個(gè)傳統(tǒng)線程時(shí),JVM會(huì)創(chuàng)建一個(gè)操作系統(tǒng)線程。一個(gè)傳統(tǒng)線程,可以輪詢執(zhí)行多個(gè)虛擬線程。

  • 虛擬線程是由傳統(tǒng)線程來(lái)執(zhí)行的,虛擬線程的調(diào)度由JVM控制,傳統(tǒng)線程的執(zhí)行和調(diào)度,由操作系統(tǒng)來(lái)控制。

  • 虛擬線程的上下文切換是由JVM控制的,因?yàn)椴簧婕暗讲僮飨到y(tǒng)級(jí)別線程的上下文切換,虛擬線程上下文切換速度非???,可以滿足高并發(fā)需求。

  • 創(chuàng)建一個(gè)虛擬線程占用的內(nèi)存非常小,相對(duì)而言,創(chuàng)建一個(gè)傳統(tǒng)線程,占用的內(nèi)存空間大。在應(yīng)用中,可以創(chuàng)建大量的虛擬線程,一般支持到百萬(wàn)級(jí),而創(chuàng)建傳統(tǒng)線程,一般只能到幾千,我們一般也不建議創(chuàng)建這么多傳統(tǒng)線程。

虛擬線程類似于task,傳統(tǒng)系統(tǒng)與操作系統(tǒng)線程對(duì)應(yīng),一個(gè)傳統(tǒng)線程可以執(zhí)行多個(gè)虛擬線程。虛擬線程與task的區(qū)別是,當(dāng)傳統(tǒng)線程執(zhí)行虛擬線程時(shí),遇到阻塞會(huì)掛起虛擬線程,當(dāng)傳統(tǒng)線程執(zhí)行task時(shí),遇到阻塞就真的阻塞了。當(dāng)然傳統(tǒng)中的task繼承自runnable,虛擬線程繼承自Thread,他們屬于不同的類,可調(diào)用的方法也不一樣。

JDK也提供了虛擬線程池,可以通過(guò)下面方式得到一個(gè)虛擬線程池。

import java.util.concurrent.*;
public class VirtualThreadPoolExample {
    public static void main(String[] args) {
        // 創(chuàng)建一個(gè)虛擬線程池
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
        // 提交多個(gè)任務(wù)到線程池
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " running in " + Thread.currentThread());
            });
        }
        // 關(guān)閉線程池
        executor.shutdown();
    }
}

上面代碼中,提交給線程池的任務(wù),JVM都會(huì)為其創(chuàng)建一個(gè)虛擬線程,然后以虛擬線程的方式執(zhí)行。

與傳統(tǒng)的線程池相比,虛擬線程池?zé)o法設(shè)置核心線程數(shù)、最大線程數(shù)、線程池大小、任務(wù)隊(duì)列等參數(shù),也不需要設(shè)置這些參數(shù)。

虛擬線程與傳統(tǒng)線程的相同之處:

  • 他們都繼承自Thread,用法一摸一樣。也都支持線程池。

  • 與傳統(tǒng)一樣,虛擬線程也有new,runnable,waiting,blocked,terminated等狀態(tài)。

  • 所有的鎖,同步機(jī)制,對(duì)虛擬線程都適用,并且與傳統(tǒng)線程一樣,虛擬線程也會(huì)有資源爭(zhēng)奪以及狀態(tài)同步問(wèn)題。并且也有上下文切換,雖然虛擬線程的上下文切換,代價(jià)非常小。

  • 異常處理機(jī)制一樣,如果遇到異常不處理,虛擬線程也會(huì)終止執(zhí)行。

虛擬線程與協(xié)程的區(qū)別

協(xié)程是python中的異步編程技術(shù),對(duì)于IO密集型應(yīng)用,協(xié)程可以發(fā)揮很大的優(yōu)勢(shì)。協(xié)程的異步工作原理與虛擬線程相似,也是遇到IO就阻塞,讓主線程繼續(xù)執(zhí)行其它任務(wù),當(dāng)IO完成時(shí),操作系統(tǒng)通過(guò)事件機(jī)制,如epoll,通知python進(jìn)程,產(chǎn)生一個(gè)事件,放到event loop隊(duì)列中,最后由主線程執(zhí)行。

虛擬線程與協(xié)程的主要區(qū)別在于:

區(qū)別虛擬線程協(xié)程
并發(fā)/并行虛擬線程是并行的,多個(gè)虛擬線程可以同時(shí)在多個(gè)CPU上運(yùn)行,同一時(shí)刻,可以運(yùn)行多個(gè)虛擬線程。從這個(gè)角度將,虛擬線程能支持更高的并發(fā)。協(xié)程不是并行的,因?yàn)橹挥幸粋€(gè)主線程執(zhí)行任務(wù)事件,同一時(shí)刻,只有一個(gè)任務(wù)被處理。
資源爭(zhēng)奪虛擬線程中,存在資源爭(zhēng)奪問(wèn)題,以及狀態(tài)同步問(wèn)題,在編寫代碼時(shí),需要考慮并發(fā)控制。甚至需要做合理的并發(fā)設(shè)計(jì)。因?yàn)橹挥幸粋€(gè)主線程在執(zhí)行任務(wù)事件,沒(méi)有并發(fā)問(wèn)題,編程時(shí)也不需要考慮并發(fā)問(wèn)題。
框架支持虛擬線程是JDK 21的新特性,不需要任何框架支持。需要框架支持,寫異步代碼和同步代碼,使用的是兩個(gè)完全不同的框架,另外學(xué)習(xí)異步編程,增加了學(xué)習(xí)成本。并且異步編程有些難度,debug也變得復(fù)雜些。

怎樣使用虛擬線程

在JDK 21中,使用虛擬線程有兩種方式:

  • 直接創(chuàng)建并啟動(dòng)虛擬線程。
public class VirtualThreadExample {
    public static void main(String[] args) {
        Thread virtualThread = Thread.ofVirtual().start(() -> {
            System.out.println("Hello virtual thread ");
        });
        try {
            virtualThread.join();  // 等待虛擬線程完成
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 通過(guò)線程池執(zhí)行虛擬線程。
import java.util.concurrent.*;
public class VirtualThreadPoolExample {
    public static void main(String[] args) {
        // 創(chuàng)建一個(gè)虛擬線程池
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
        // 提交多個(gè)任務(wù)到線程池
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " running in " + Thread.currentThread());
            });
        }
        // 關(guān)閉線程池
        executor.shutdown();
    }
}

通過(guò)線程池執(zhí)行任務(wù)時(shí),無(wú)法對(duì)并發(fā)實(shí)現(xiàn)控制,容易造成OOM,或耗盡服務(wù)方資源,可以自定義以下虛擬線程池,實(shí)現(xiàn)資源控制:

package com.zengbiaobiao.demo.vitrualthreaddemo;
import org.springframework.lang.NonNull;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/*****
 * 虛擬線程池,支持配置任務(wù)隊(duì)列數(shù)和最大并發(fā)任務(wù)數(shù)
 */
public class VirtualThreadExecutorService extends AbstractExecutorService {
    private volatile boolean shouldStop = false;
    private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
    private final Semaphore semaphore;
    private final BlockingQueue<Runnable> taskQueue;
    /******
     * 構(gòu)造函數(shù)
     * @param taskQueueSize,任務(wù)隊(duì)列大小,任務(wù)隊(duì)列是一個(gè)阻塞隊(duì)列,如果任務(wù)隊(duì)列滿了,那么調(diào)用execute方法會(huì)阻塞
     * @param concurrencySize,并發(fā)任務(wù)大小,同時(shí)執(zhí)行的IO任務(wù)個(gè)數(shù),防止并發(fā)過(guò)重,或者資源不夠
     */
    public VirtualThreadExecutorService(int taskQueueSize, int concurrencySize) {
        this.semaphore = new Semaphore(concurrencySize);
        taskQueue = new LinkedBlockingQueue<>(taskQueueSize);
        this.loopEvent();
    }
    private void loopEvent() {
        Thread.ofVirtual().name("VirtualThreadExecutor").start(() -> {
            while (!shouldStop) {
                try {
                    Runnable task = taskQueue.take();
                    semaphore.acquire();
                    executor.execute(() -> {
                        try {
                            try {
                                task.run();
                            } finally {
                                semaphore.release();
                            }
                        } catch (Exception e) {
                            Thread.currentThread().interrupt();
                            throw new RuntimeException(e);
                        }
                    });
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    if (shouldStop) break;
                }
            }
        });
    }
    @Override
    public void shutdown() {
        shouldStop = true;
        executor.shutdown();
    }
    /**
     * @return The task not executed
     */
    @Override
    public List<Runnable> shutdownNow() {
        shouldStop = true;
        List<Runnable> remainingTasks = new ArrayList<>(taskQueue);
        taskQueue.clear();
        executor.shutdownNow();
        return remainingTasks;
    }
    @Override
    public boolean isShutdown() {
        return shouldStop;
    }
    @Override
    public boolean isTerminated() {
        return shouldStop && executor.isTerminated();
    }
    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return executor.awaitTermination(timeout, unit);
    }
    @Override
    public void execute(Runnable command) {
        try {
            taskQueue.put(command); // 阻塞直到隊(duì)列有空間
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RejectedExecutionException("Task submission interrupted.", e);
        }
    }
}

測(cè)試代碼如下:

package com.zengbiaobiao.demo.vitrualthreaddemo;
import org.apache.tomcat.util.threads.VirtualThreadExecutor;
public class VirtualThreadExecutorServiceDemo {
    public static void main(String[] args) throws InterruptedException {
        VirtualThreadExecutorService executorService = new VirtualThreadExecutorService(10, 2);
        for (int i = 0; i < 100000; i++) {
            final String threadName = "thread-" + i;
            System.out.println(Thread.currentThread() + ": try to create task " + threadName);
            executorService.submit(() -> {
                System.out.println(Thread.currentThread() + ": " + threadName + " created!");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread() + ": " + threadName + " finished!");
            });
        }
        Thread.sleep(5000000);
    }
}

哪些場(chǎng)景下可以應(yīng)用虛擬線程

虛擬線程在IO密集型的高并發(fā)應(yīng)用中能發(fā)揮出巨大的威力,在所有IO密集型應(yīng)用中,具體來(lái)說(shuō),下列場(chǎng)景中,使用虛擬線程是比較合適的:

  • 短時(shí)間需要完成的任務(wù),且沒(méi)有資源爭(zhēng)奪或亂序問(wèn)題,比如數(shù)據(jù)庫(kù)寫入,服務(wù)器 HTTP 請(qǐng)求處理,遠(yuǎn)程 RESTful API 調(diào)用,RabbitMQ 消息處理等應(yīng)用場(chǎng)景。。

  • 長(zhǎng)時(shí)間運(yùn)行的任務(wù),但是對(duì)消息處理由順序要求的任務(wù)。比如在電梯監(jiān)控系統(tǒng)中,需要對(duì)每臺(tái)電梯的數(shù)據(jù)進(jìn)行處理,但是需要保證消息被處理的順序。這時(shí)可以為每臺(tái)電梯創(chuàng)建一個(gè)虛擬線程,這臺(tái)電梯的數(shù)據(jù)交給專門的虛擬線程處理。因?yàn)閼?yīng)用中可以創(chuàng)建大量虛擬線程,并且虛擬線程一般都是異步處理任務(wù),所以這個(gè)場(chǎng)景中,使用虛擬線程,可以滿足高性能和高并發(fā)的要求。

  • API網(wǎng)關(guān)中,對(duì)多個(gè)上游API數(shù)據(jù)進(jìn)行查詢,組裝合并,使用虛擬線程,相比傳統(tǒng)線程,效果更佳。虛擬線程,也支持CountDownLatch,Semaphore等工具類。

  • 事件驅(qū)動(dòng)的架構(gòu)中,使用虛擬線程,效果也很好。比如spring boot中的異步事件,默認(rèn)使用的是傳統(tǒng)線程池,如果將其改成虛擬線程池,并發(fā)處理能力可以極大提高。

那么哪些場(chǎng)景下不合適使用虛擬線程呢?

  • CPU密集型應(yīng)用,比如大數(shù)據(jù)處理、圖像處理、矩陣運(yùn)算等。

  • 如果應(yīng)用有很高的并發(fā)資源爭(zhēng)奪,或者狀態(tài)同步,并且造成系統(tǒng)吞吐量低,需要考慮優(yōu)化并發(fā)模型,這種場(chǎng)景下,不但傳統(tǒng)線程不合適,虛擬線程也不合適。

虛擬線程實(shí)際應(yīng)用場(chǎng)景舉例

在一個(gè)spring boot項(xiàng)目中,有時(shí)候因?yàn)楫惒绞录幚聿贿^(guò)來(lái),造成吞吐量下降,在JDK 21中,可以將事件改成虛擬線程來(lái)執(zhí)行,代碼如下:

package com.zengbiaobiao.demo.vitrualthreaddemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        // 最大并行任務(wù)數(shù)
        Semaphore semaphore = new Semaphore(100);
        ExecutorService virtualThreadPool = Executors.newVirtualThreadPerTaskExecutor();
        return runnable -> {
            try {
                // 控制并行任務(wù)數(shù)
                semaphore.acquire();
                virtualThreadPool.submit(() -> {
                    try {
                        runnable.run();
                    } finally {
                        semaphore.release();
                    }
                });
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Task submission interrupted", e);
            }
        };
    }
}

事件發(fā)送和處理代碼如下:

package com.zengbiaobiao.demo.vitrualthreaddemo;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/home")
public class HomeController {
    private final ApplicationEventPublisher eventPublisher;
    public HomeController(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }
    @GetMapping("/index")
    public String index() {
        for (int i = 0; i < 1000; i++) {
            eventPublisher.publishEvent("event " + i);
        }
        return "success";
    }
    @EventListener
    @Async
    public void handleEvent(String event) {
        System.out.println(Thread.currentThread() + ": " + event);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

輸出結(jié)果如下:

VirtualThread[#2031]/runnable@ForkJoinPool-1-worker-4: event 976
VirtualThread[#2039]/runnable@ForkJoinPool-1-worker-1: event 980
VirtualThread[#1064]/runnable@ForkJoinPool-1-worker-1: event 983
VirtualThread[#2047]/runnable@ForkJoinPool-1-worker-2: event 984
VirtualThread[#2049]/runnable@ForkJoinPool-1-worker-9: event 985
VirtualThread[#2057]/runnable@ForkJoinPool-1-worker-2: event 989
VirtualThread[#2059]/runnable@ForkJoinPool-1-worker-3: event 990
VirtualThread[#2061]/runnable@ForkJoinPool-1-worker-6: event 991
VirtualThread[#2063]/runnable@ForkJoinPool-1-worker-10: event 992
VirtualThread[#2065]/runnable@ForkJoinPool-1-worker-10: event 993
VirtualThread[#2071]/runnable@ForkJoinPool-1-worker-3: event 996
VirtualThread[#2069]/runnable@ForkJoinPool-1-worker-2: event 995
VirtualThread[#2075]/runnable@ForkJoinPool-1-worker-7: event 998
VirtualThread[#2077]/runnable@ForkJoinPool-1-worker-10: event 999

上面輸出結(jié)果中,每次并發(fā)執(zhí)行100個(gè)任務(wù),當(dāng)虛擬線程池任務(wù)達(dá)到100之后,執(zhí)行eventPublisher.publishEvent("event " + i)代碼時(shí),代碼阻塞,過(guò)100ms之后,100個(gè)任務(wù)執(zhí)行完成,下一批任務(wù)被執(zhí)行。

虛擬線程使用注意事項(xiàng)

  • 搞清楚任務(wù)類型,是IO密集型,還是CPU密集型

  • 與傳統(tǒng)線程結(jié)合使用

  • 關(guān)注性能和資源,使用虛擬線程無(wú)法通過(guò)線程池等工具控制并發(fā),需要借助Semepha,CountdownLatch等工具才能限流,如果不限流,容易造成OOM,或?qū)δ繕?biāo)系統(tǒng)造成巨大流量沖擊。

  • 在異步框架中,關(guān)注隱藏的傳統(tǒng)線程,比如在HttpClient的異步請(qǐng)求中,每次異步請(qǐng)求都會(huì)創(chuàng)建一個(gè)HttpClient回調(diào)線程。大量的傳統(tǒng)線程被間接創(chuàng)建,也容易引起OOM。

  • 由synchronized關(guān)鍵字引起的pinned問(wèn)題,看起來(lái)在JDK 21中,做了一些優(yōu)化,即便虛擬線程pinned到傳統(tǒng)線程,也只是性能退回到傳統(tǒng)線程,無(wú)非是慢一點(diǎn),反而不是太大問(wèn)題。經(jīng)過(guò)大量測(cè)試,發(fā)現(xiàn)基本只出現(xiàn)一次,之后不會(huì)再出現(xiàn)。不過(guò)使用ReentrantLock,效果確實(shí)會(huì)好很多,將synchronized關(guān)鍵字改成lock.()和lock.unlock(),F(xiàn)orkJoinPool中的線程數(shù)量會(huì)降低,并且任務(wù)分配均衡。

  • 不要忽略軟件設(shè)計(jì),尤其在需要大量同步的應(yīng)用中。

經(jīng)過(guò)驗(yàn)證,虛擬線程在遇到IO時(shí),確實(shí)會(huì)讓步,并且不消耗太多資源,核心特點(diǎn)是,讓異步編程變得簡(jiǎn)單,并且不需要框架支持。但是容易因大的并發(fā),造成OOM,或者對(duì)目標(biāo)系統(tǒng)造成沖擊,追求高并發(fā)可用,但一定要做測(cè)試和驗(yàn)證。對(duì)于需要做狀態(tài)同步,如需要加鎖,或需要使用synchronize關(guān)鍵字的代碼,需要優(yōu)化設(shè)計(jì),如果無(wú)法規(guī)避,那么,使用虛擬線程,和使用線程池,效果差不多。

虛擬線程存在的問(wèn)題:

Java Virtual Threads — some early gotchas to look out for

Two Pitfalls by moving to Java Virtual Threads

Java 21 Virtual Threads - Dude, Where’s My Lock?

Pitfalls to avoid when switching to Virtual threads

Do Java 21 virtual threads address the main reason to switch to reactive single-thread frameworks?

Pinning: A pitfall to avoid when using virtual threads in Java

Taming the Virtual Threads: Embracing Concurrency With Pitfall Avoidance

Pitfalls you encounter with virtual threads

示例代碼在Gitee上同步

到此這篇關(guān)于Java 虛擬線程 探索的文章就介紹到這了,更多相關(guān)Java 虛擬線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot2.x只需兩步快速整合log4j2的方法

    springboot2.x只需兩步快速整合log4j2的方法

    這篇文章主要介紹了springboot2.x只需兩步快速整合log4j2的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • SpringMvc使用GoogleKaptcha生成驗(yàn)證碼

    SpringMvc使用GoogleKaptcha生成驗(yàn)證碼

    這篇文章主要為大家詳細(xì)介紹了SpringMvc項(xiàng)目中使用GoogleKaptcha 生成驗(yàn)證碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • PowerJob的IdGenerateService工作流程源碼解讀

    PowerJob的IdGenerateService工作流程源碼解讀

    這篇文章主要為大家介紹了PowerJob的IdGenerateService工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Java并發(fā)編程中的生產(chǎn)者與消費(fèi)者模型簡(jiǎn)述

    Java并發(fā)編程中的生產(chǎn)者與消費(fèi)者模型簡(jiǎn)述

    這篇文章主要介紹了Java并發(fā)編程中的生產(chǎn)者與消費(fèi)者模型簡(jiǎn)述,多線程并發(fā)是Java編程中最終要的部分之一,需要的朋友可以參考下
    2015-07-07
  • 使用SpringBoot+nmap4j獲取端口信息的代碼詳解

    使用SpringBoot+nmap4j獲取端口信息的代碼詳解

    這篇文章主要介紹了使用 SpringBoot + nmap4j 獲取端口信息,包括需求背景、nmap4j 的相關(guān)介紹、代碼說(shuō)明(含測(cè)試代碼、改造后的代碼及參數(shù)說(shuō)明),還提到了文件讀取方式和依賴引入方式,最終請(qǐng)求能獲取到數(shù)據(jù),需要的朋友可以參考下
    2025-01-01
  • 詳解Mybatis多參數(shù)傳遞入?yún)⑺姆N處理方式

    詳解Mybatis多參數(shù)傳遞入?yún)⑺姆N處理方式

    這篇文章主要介紹了詳解Mybatis多參數(shù)傳遞入?yún)⑺姆N處理方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • JDBC使用小結(jié)

    JDBC使用小結(jié)

    JDBC是一個(gè)Java應(yīng)用程序接口,作用是封裝了對(duì)數(shù)據(jù)庫(kù)的各種操作。JDBC由類和接口組成,使用Java開發(fā)數(shù)據(jù)庫(kù)應(yīng)用都需要4個(gè)主要的接口:Driver、Connection、Statement、ResultSet,這些接口定義了使用SQL訪問(wèn)數(shù)據(jù)庫(kù)的一般架構(gòu),下面我們來(lái)詳細(xì)探討下jdbc的使用。
    2016-05-05
  • mybatis(mybatis-plus)映射文件(XML文件)中特殊字符轉(zhuǎn)義的實(shí)現(xiàn)

    mybatis(mybatis-plus)映射文件(XML文件)中特殊字符轉(zhuǎn)義的實(shí)現(xiàn)

    XML 文件在解析時(shí)會(huì)將五種特殊字符進(jìn)行轉(zhuǎn)義,本文主要介紹了mybatis(mybatis-plus)映射文件(XML文件)中特殊字符轉(zhuǎn)義的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-12-12
  • SpringBoot上傳文件如何返回前端進(jìn)度條

    SpringBoot上傳文件如何返回前端進(jìn)度條

    這篇文章主要介紹了SpringBoot上傳文件如何返回前端進(jìn)度條問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 詳解ssh框架原理及流程

    詳解ssh框架原理及流程

    在本文中小編給大家整理的是關(guān)于ssh框架原理及流程的相關(guān)知識(shí)點(diǎn)內(nèi)容,有此需要的朋友們可以學(xué)習(xí)下。
    2019-07-07

最新評(píng)論