面試官:談?wù)勀銓?duì)虛擬線程的理解?
操作系統(tǒng)線程、普通線程(Java 線程)和虛擬線程的關(guān)系如下:
虛擬線程使用
虛擬線程的創(chuàng)建方式,主要有以下 4 種:
- Thread.startVirtualThread(Runnable task)
- Thread.ofVirtual().unstarted(Runnable task)
- Thread.ofVirtual().factory()
- Executors.newVirtualThreadPerTaskExecutor()
具體示例如下。
1.startVirtualThread
創(chuàng)建虛擬線程,并直接啟動(dòng)執(zhí)行任務(wù):
// 創(chuàng)建并啟動(dòng)虛擬線程
Thread.startVirtualThread(() -> {
System.out.println("Do virtual thread.");
});
2.unstarted
只創(chuàng)建虛擬線程,但不直接啟動(dòng):
// 創(chuàng)建虛擬線程
Thread vt = Thread.ofVirtual().unstarted(()->{
System.out.println("Do virtual thread.");
});
// 運(yùn)行虛擬線程
vt.start();
3.factory
先創(chuàng)建虛擬線程工廠,然后再使用工廠創(chuàng)建虛擬線程,之后再調(diào)用 start() 方法進(jìn)行執(zhí)行:
// 創(chuàng)建虛擬線程工廠
ThreadFactory tf = Thread.ofVirtual().factory();
// 創(chuàng)建虛擬線程
Thread vt = tf.newThread(()->{
System.out.println("Do virtual thread.");
});
// 運(yùn)行虛擬線程
vt.start();
4.newVirtualThreadPerTaskExecutor
使用線程池的方式創(chuàng)建虛擬線程:
// 創(chuàng)建一個(gè)支持虛擬線程的線程池
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
executor.submit(()->{
System.out.println("Do virtual thread.");
});
虛擬線程 VS 普通線程
虛擬線程和普通線程的區(qū)別主要體現(xiàn)在以下幾點(diǎn):
- 普通線程是和操作系統(tǒng)的物理線程是一一對(duì)應(yīng)的,而虛擬線程是 JVM 層面的邏輯線程,并不和操作系統(tǒng)的物理線程一一對(duì)應(yīng),它可以看作是輕量級(jí)的線程。
- 普通線程默認(rèn)創(chuàng)建的是用戶線程(而守護(hù)線程),而虛擬線程是守護(hù)線程,并且其守護(hù)線程的屬性不能被修改,如果修改就會(huì)報(bào)錯(cuò),如下圖所示:
- 虛擬線程由 JVM 調(diào)度和使用,避免了普通線程頻繁切換的性能開(kāi)銷,所以相比于普通的線程來(lái)說(shuō),運(yùn)行效率更高。
小結(jié)
線程是輕量級(jí)的進(jìn)程,而虛擬線程則是輕量級(jí)的線程,虛擬線程是 JVM 層面實(shí)現(xiàn)的邏輯線程,不直接和操作系統(tǒng)的物理線程一一對(duì)應(yīng),因此使用它可以減少線程上下文切換所帶來(lái)的性能開(kāi)銷。它和普通線程的線程類型也不同,普通線程是默認(rèn)是用戶線程類型,而虛擬線程則是守護(hù)線程(而且不能被修改)。