使用虚线程进行网络 IO

接下来编写代码:

//Java 16 中的 Record 对象,可以理解为有包含两个 final 属性(url 和 response)的类
static record URLData (URL url, byte[] response) { }

static List retrieveURLs(URL… urls) throws Exception {
//创建虚拟线程线程池
try (var executor = Executors.newVirtualThreadExecutor()) {
//生成读取对每个 url 执行 getURL 方法的任务
var tasks = Arrays.stream(urls)
.map(url -> (Callable)() -> getURL(url))
.toList();
//提交任务,等待并返回所有结果
return executor.submit(tasks)
.filter(Future::isCompletedNormally)
.map(Future::join)
.toList();
}
}

//读取url的内容
static URLData getURL(URL url) throws IOException {
try (InputStream in = url.openStream()) {
return new URLData(url, in.readAllBytes());
}
}

public static void main(String[] args) throws Exception {
//访问 google,由于你懂得,会比较慢
List urlData = retrieveURLs(new URL(“https://www.google.com/”));
}
我们使用 retrieveURLs 访问谷歌,肯定会很慢,来保证能采集到堆栈。同时,不能用 jstack 采集堆栈(目前 jstack 采集不到虚拟线程堆栈,只能采集到承载线程的堆栈),需要用 jcmd 命令中的 JavaThread.dump 采集。同时,为了能采集到我们想要的堆栈,我们需要一些小操作。

首先,我们在 getURL(URL url) 方法的第一行打断点,debug 到这里暂停。然后执行命令:

jps
25496 LoomThreadMain
12512 Jps

jcmd 25496 JavaThread.dump threads.txt -overwrite
然后继续执行程序,再执行命令,采集虚拟线程执行 I/O 操作时候的堆栈:

jcmd 25496 JavaThread.dump threads2.txt -overwrite
我们查看threads.txt这个文件,其中我们关心的线程信息是:

“main” #1
java.base@17-loom/jdk.internal.misc.Unsafe.park(Native Method)
java.base@17-loom/java.util.concurrent.locks.LockSupport.park(LockSupport.java:371)
java.base@17-loom/java.util.concurrent.LinkedTransferQueue N o d e . b l o c k ( L i n k e d T r a n s f e r Q u e u e . j a v a : 470 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . F o r k J o i n P o o l . u n m a n a g e d B l o c k ( F o r k J o i n P o o l . j a v a : 3470 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . F o r k J o i n P o o l . m a n a g e d B l o c k ( F o r k J o i n P o o l . j a v a : 3441 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . L i n k e d T r a n s f e r Q u e u e . a w a i t M a t c h ( L i n k e d T r a n s f e r Q u e u e . j a v a : 669 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . L i n k e d T r a n s f e r Q u e u e . x f e r ( L i n k e d T r a n s f e r Q u e u e . j a v a : 616 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . L i n k e d T r a n s f e r Q u e u e . t a k e ( L i n k e d T r a n s f e r Q u e u e . j a v a : 1286 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e H e l p e r Node.block(LinkedTransferQueue.java:470) java.base@17-loom/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3470) java.base@17-loom/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3441) java.base@17-loom/java.util.concurrent.LinkedTransferQueue.awaitMatch(LinkedTransferQueue.java:669) java.base@17-loom/java.util.concurrent.LinkedTransferQueue.xfer(LinkedTransferQueue.java:616) java.base@17-loom/java.util.concurrent.LinkedTransferQueue.take(LinkedTransferQueue.java:1286) java.base@17-loom/java.util.concurrent.ExecutorServiceHelper Node.block(LinkedTransferQueue.java:470)java.base@17loom/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3470)java.base@17loom/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3441)java.base@17loom/java.util.concurrent.LinkedTransferQueue.awaitMatch(LinkedTransferQueue.java:669)java.base@17loom/java.util.concurrent.LinkedTransferQueue.xfer(LinkedTransferQueue.java:616)java.base@17loom/java.util.concurrent.LinkedTransferQueue.take(LinkedTransferQueue.java:1286)java.base@17loom/java.util.concurrent.ExecutorServiceHelperBlockingQueueSpliterator.tryAdvance(ExecutorServiceHelper.java:197)
java.base@17-loom/java.util.Spliterator.forEachRemaining(Spliterator.java:326)
java.base@17-loom/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
java.base@17-loom/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
java.base@17-loom/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:550)
java.base@17-loom/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
java.base@17-loom/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
java.base@17-loom/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
java.base@17-loom/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
app//com.github.hashjang.LoomThreadMain.retrieveURLs(LoomThreadMain.java:43)
app//com.github.hashjang.LoomThreadMain.main(LoomThreadMain.java:29)

“ForkJoinPool-1-worker-1” #27
java.base@17-loom/java.lang.Continuation.run(Continuation.java:300)
java.base@17-loom/java.lang.VirtualThread.runContinuation(VirtualThread.java:240)
java.base@17-loom/java.lang.VirtualThreadKaTeX parse error: Can't use function '$' in math mode at position 7: Lambda$̲25/0x0000000801… c a p t u r e ( F o r k J o i n T a s k . j a v a : 373 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . F o r k J o i n T a s k . d o E x e c ( F o r k J o i n T a s k . j a v a ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . F o r k J o i n P o o l capture(ForkJoinTask.java:373) java.base@17-loom/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java) java.base@17-loom/java.util.concurrent.ForkJoinPool capture(ForkJoinTask.java:373)java.base@17loom/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)java.base@17loom/java.util.concurrent.ForkJoinPoolWorkQueue.topLevelExec(ForkJoinPool.java:1177)
java.base@17-loom/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1648)
java.base@17-loom/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1615)
java.base@17-loom/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

“” #26 virtual
java.base/java.util.concurrent.ConcurrentHashMap.transfer(ConcurrentHashMap.java:2431)
java.base/java.util.concurrent.ConcurrentHashMap.addCount(ConcurrentHashMap.java:2354)
java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1075)
java.base/java.util.concurrent.ConcurrentHashMap.putIfAbsent(ConcurrentHashMap.java:1541)
java.base/sun.util.locale.LocaleObjectCache.get(LocaleObjectCache.java:68)
java.base/java.util.Locale.getInstance(Locale.java:841)
java.base/java.util.Locale.forLanguageTag(Locale.java:1736)
java.base/sun.util.locale.provider.LocaleProviderAdapter.toLocaleArray(LocaleProviderAdapter.java:323)
java.base/sun.util.locale.provider.CalendarDataProviderImpl.getAvailableLocales(CalendarDataProviderImpl.java:63)
java.base/java.util.spi.LocaleServiceProvider.isSupportedLocale(LocaleServiceProvider.java:217)
java.base/sun.util.locale.provider.LocaleServiceProviderPool.findProviders(LocaleServiceProviderPool.java:306)
java.base/sun.util.locale.provider.LocaleServiceProviderPool.getLocalizedObjectImpl(LocaleServiceProviderPool.java:274)
java.base/sun.util.locale.provider.LocaleServiceProviderPool.getLocalizedObject(LocaleServiceProviderPool.java:256)
java.base/sun.util.locale.provider.CalendarDataUtility.retrieveFirstDayOfWeek(CalendarDataUtility.java:76)
java.base/java.util.Calendar.setWeekCountData(Calendar.java:3419)
java.base/java.util.Calendar.(Calendar.java:1612)
java.base/java.util.GregorianCalendar.(GregorianCalendar.java:738)
java.base/java.util.Calendar B u i l d e r . b u i l d ( C a l e n d a r . j a v a : 1494 ) j a v a . b a s e / s u n . u t i l . l o c a l e . p r o v i d e r . C a l e n d a r P r o v i d e r I m p l . g e t I n s t a n c e ( C a l e n d a r P r o v i d e r I m p l . j a v a : 87 ) j a v a . b a s e / j a v a . u t i l . C a l e n d a r . c r e a t e C a l e n d a r ( C a l e n d a r . j a v a : 1697 ) j a v a . b a s e / j a v a . u t i l . C a l e n d a r . g e t I n s t a n c e ( C a l e n d a r . j a v a : 1661 ) j a v a . b a s e / j a v a . t e x t . S i m p l e D a t e F o r m a t . i n i t i a l i z e C a l e n d a r ( S i m p l e D a t e F o r m a t . j a v a : 680 ) j a v a . b a s e / j a v a . t e x t . S i m p l e D a t e F o r m a t . < i n i t > ( S i m p l e D a t e F o r m a t . j a v a : 624 ) j a v a . b a s e / j a v a . t e x t . S i m p l e D a t e F o r m a t . < i n i t > ( S i m p l e D a t e F o r m a t . j a v a : 603 ) j a v a . b a s e / s u n . s e c u r i t y . u t i l . D i s a b l e d A l g o r i t h m C o n s t r a i n t s Builder.build(Calendar.java:1494) java.base/sun.util.locale.provider.CalendarProviderImpl.getInstance(CalendarProviderImpl.java:87) java.base/java.util.Calendar.createCalendar(Calendar.java:1697) java.base/java.util.Calendar.getInstance(Calendar.java:1661) java.base/java.text.SimpleDateFormat.initializeCalendar(SimpleDateFormat.java:680) java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:624) java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:603) java.base/sun.security.util.DisabledAlgorithmConstraints Builder.build(Calendar.java:1494)java.base/sun.util.locale.provider.CalendarProviderImpl.getInstance(CalendarProviderImpl.java:87)java.base/java.util.Calendar.createCalendar(Calendar.java:1697)java.base/java.util.Calendar.getInstance(Calendar.java:1661)java.base/java.text.SimpleDateFormat.initializeCalendar(SimpleDateFormat.java:680)java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:624)java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:603)java.base/sun.security.util.DisabledAlgorithmConstraintsDenyAfterConstraint.(DisabledAlgorithmConstraints.java:695)
java.base/sun.security.util.DisabledAlgorithmConstraints C o n s t r a i n t s . < i n i t > ( D i s a b l e d A l g o r i t h m C o n s t r a i n t s . j a v a : 424 ) j a v a . b a s e / s u n . s e c u r i t y . u t i l . D i s a b l e d A l g o r i t h m C o n s t r a i n t s . < i n i t > ( D i s a b l e d A l g o r i t h m C o n s t r a i n t s . j a v a : 149 ) j a v a . b a s e / s u n . s e c u r i t y . s s l . S S L A l g o r i t h m C o n s t r a i n t s . < c l i n i t > ( S S L A l g o r i t h m C o n s t r a i n t s . j a v a : 49 ) j a v a . b a s e / s u n . s e c u r i t y . s s l . P r o t o c o l V e r s i o n . < i n i t > ( P r o t o c o l V e r s i o n . j a v a : 158 ) j a v a . b a s e / s u n . s e c u r i t y . s s l . P r o t o c o l V e r s i o n . < c l i n i t > ( P r o t o c o l V e r s i o n . j a v a : 41 ) j a v a . b a s e / s u n . s e c u r i t y . s s l . S S L C o n t e x t I m p l Constraints.<init>(DisabledAlgorithmConstraints.java:424) java.base/sun.security.util.DisabledAlgorithmConstraints.<init>(DisabledAlgorithmConstraints.java:149) java.base/sun.security.ssl.SSLAlgorithmConstraints.<clinit>(SSLAlgorithmConstraints.java:49) java.base/sun.security.ssl.ProtocolVersion.<init>(ProtocolVersion.java:158) java.base/sun.security.ssl.ProtocolVersion.<clinit>(ProtocolVersion.java:41) java.base/sun.security.ssl.SSLContextImpl Constraints.<init>(DisabledAlgorithmConstraints.java:424)java.base/sun.security.util.DisabledAlgorithmConstraints.<init>(DisabledAlgorithmConstraints.java:149)java.base/sun.security.ssl.SSLAlgorithmConstraints.<clinit>(SSLAlgorithmConstraints.java:49)java.base/sun.security.ssl.ProtocolVersion.<init>(ProtocolVersion.java:158)java.base/sun.security.ssl.ProtocolVersion.<clinit>(ProtocolVersion.java:41)java.base/sun.security.ssl.SSLContextImplAbstractTLSContext.(SSLContextImpl.java:539)
java.base/java.lang.Class.forName0(Native Method)
java.base/java.lang.Class.forName(Class.java:375)
java.base/java.security.Provider S e r v i c e . g e t I m p l C l a s s ( P r o v i d e r . j a v a : 1937 ) j a v a . b a s e / j a v a . s e c u r i t y . P r o v i d e r Service.getImplClass(Provider.java:1937) java.base/java.security.Provider Service.getImplClass(Provider.java:1937)java.base/java.security.ProviderService.getDefaultConstructor(Provider.java:1968)
java.base/java.security.Provider S e r v i c e . n e w I n s t a n c e O f ( P r o v i d e r . j a v a : 1882 ) j a v a . b a s e / j a v a . s e c u r i t y . P r o v i d e r Service.newInstanceOf(Provider.java:1882) java.base/java.security.Provider Service.newInstanceOf(Provider.java:1882)java.base/java.security.ProviderService.newInstanceUtil(Provider.java:1890)
java.base/java.security.Provider S e r v i c e . n e w I n s t a n c e ( P r o v i d e r . j a v a : 1865 ) j a v a . b a s e / s u n . s e c u r i t y . j c a . G e t I n s t a n c e . g e t I n s t a n c e ( G e t I n s t a n c e . j a v a : 236 ) j a v a . b a s e / s u n . s e c u r i t y . j c a . G e t I n s t a n c e . g e t I n s t a n c e ( G e t I n s t a n c e . j a v a : 164 ) j a v a . b a s e / j a v a x . n e t . s s l . S S L C o n t e x t . g e t I n s t a n c e ( S S L C o n t e x t . j a v a : 184 ) j a v a . b a s e / j a v a x . n e t . s s l . S S L C o n t e x t . g e t D e f a u l t ( S S L C o n t e x t . j a v a : 110 ) j a v a . b a s e / j a v a x . n e t . s s l . S S L S o c k e t F a c t o r y . g e t D e f a u l t ( S S L S o c k e t F a c t o r y . j a v a : 83 ) j a v a . b a s e / j a v a x . n e t . s s l . H t t p s U R L C o n n e c t i o n . g e t D e f a u l t S S L S o c k e t F a c t o r y ( H t t p s U R L C o n n e c t i o n . j a v a : 334 ) j a v a . b a s e / j a v a x . n e t . s s l . H t t p s U R L C o n n e c t i o n . < i n i t > ( H t t p s U R L C o n n e c t i o n . j a v a : 291 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p s . H t t p s U R L C o n n e c t i o n I m p l . < i n i t > ( H t t p s U R L C o n n e c t i o n I m p l . j a v a : 81 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p s . H a n d l e r . o p e n C o n n e c t i o n ( H a n d l e r . j a v a : 62 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p s . H a n d l e r . o p e n C o n n e c t i o n ( H a n d l e r . j a v a : 57 ) j a v a . b a s e / j a v a . n e t . U R L . o p e n C o n n e c t i o n ( U R L . j a v a : 1093 ) j a v a . b a s e / j a v a . n e t . U R L . o p e n S t r e a m ( U R L . j a v a : 1159 ) c o m . g i t h u b . h a s h j a n g . L o o m T h r e a d M a i n . g e t U R L ( L o o m T h r e a d M a i n . j a v a : 48 ) c o m . g i t h u b . h a s h j a n g . L o o m T h r e a d M a i n . l a m b d a Service.newInstance(Provider.java:1865) java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236) java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164) java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:184) java.base/javax.net.ssl.SSLContext.getDefault(SSLContext.java:110) java.base/javax.net.ssl.SSLSocketFactory.getDefault(SSLSocketFactory.java:83) java.base/javax.net.ssl.HttpsURLConnection.getDefaultSSLSocketFactory(HttpsURLConnection.java:334) java.base/javax.net.ssl.HttpsURLConnection.<init>(HttpsURLConnection.java:291) java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.<init>(HttpsURLConnectionImpl.java:81) java.base/sun.net.www.protocol.https.Handler.openConnection(Handler.java:62) java.base/sun.net.www.protocol.https.Handler.openConnection(Handler.java:57) java.base/java.net.URL.openConnection(URL.java:1093) java.base/java.net.URL.openStream(URL.java:1159) com.github.hashjang.LoomThreadMain.getURL(LoomThreadMain.java:48) com.github.hashjang.LoomThreadMain.lambda Service.newInstance(Provider.java:1865)java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:184)java.base/javax.net.ssl.SSLContext.getDefault(SSLContext.java:110)java.base/javax.net.ssl.SSLSocketFactory.getDefault(SSLSocketFactory.java:83)java.base/javax.net.ssl.HttpsURLConnection.getDefaultSSLSocketFactory(HttpsURLConnection.java:334)java.base/javax.net.ssl.HttpsURLConnection.<init>(HttpsURLConnection.java:291)java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.<init>(HttpsURLConnectionImpl.java:81)java.base/sun.net.www.protocol.https.Handler.openConnection(Handler.java:62)java.base/sun.net.www.protocol.https.Handler.openConnection(Handler.java:57)java.base/java.net.URL.openConnection(URL.java:1093)java.base/java.net.URL.openStream(URL.java:1159)com.github.hashjang.LoomThreadMain.getURL(LoomThreadMain.java:48)com.github.hashjang.LoomThreadMain.lambdaretrieveURLs 0 ( L o o m T h r e a d M a i n . j a v a : 38 ) j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . F u t u r e T a s k . r u n 0(LoomThreadMain.java:38) java.base/java.util.concurrent.FutureTask.run 0(LoomThreadMain.java:38)java.base/java.util.concurrent.FutureTask.run$ c a p t u r e ( F u t u r e T a s k . j a v a : 295 ) j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . F u t u r e T a s k . r u n ( F u t u r e T a s k . j a v a ) j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . T h r e a d E x e c u t o r capture(FutureTask.java:295) java.base/java.util.concurrent.FutureTask.run(FutureTask.java) java.base/java.util.concurrent.ThreadExecutor capture(FutureTask.java:295)java.base/java.util.concurrent.FutureTask.run(FutureTask.java)java.base/java.util.concurrent.ThreadExecutorTaskRunner.run(ThreadExecutor.java:385)
java.base/java.lang.VirtualThread.run(VirtualThread.java:295)
java.base/java.lang.VirtualThread V T h r e a d C o n t i n u a t i o n . l a m b d a VThreadContinuation.lambda VThreadContinuation.lambdanew$0(VirtualThread.java:172)
java.base/java.lang.Continuation.enter0(Continuation.java:372)
java.base/java.lang.Continuation.enter(Continuation.java:365)

其中 “” #26 virtual 是我们程序中创建的虚拟线程,并且通过堆栈中可以看出,虚拟线程还没有处于 I/O 操作。通过线程堆栈也可以看出,这个虚拟线程的承载线程是 “ForkJoinPool-1-worker-1” #27. 可以看出虚拟线程默认的承载线程是 Java 8 之后默认会启动的 common ForkJoinPool 中的线程。并且是通过 Continuation 这个类执行虚拟线程的工作的。

查看threads2.txt:

“main” #1
java.base@17-loom/jdk.internal.misc.Unsafe.park(Native Method)
java.base@17-loom/java.util.concurrent.locks.LockSupport.park(LockSupport.java:371)
java.base@17-loom/java.util.concurrent.LinkedTransferQueue N o d e . b l o c k ( L i n k e d T r a n s f e r Q u e u e . j a v a : 470 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . F o r k J o i n P o o l . u n m a n a g e d B l o c k ( F o r k J o i n P o o l . j a v a : 3470 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . F o r k J o i n P o o l . m a n a g e d B l o c k ( F o r k J o i n P o o l . j a v a : 3441 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . L i n k e d T r a n s f e r Q u e u e . a w a i t M a t c h ( L i n k e d T r a n s f e r Q u e u e . j a v a : 669 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . L i n k e d T r a n s f e r Q u e u e . x f e r ( L i n k e d T r a n s f e r Q u e u e . j a v a : 616 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . L i n k e d T r a n s f e r Q u e u e . t a k e ( L i n k e d T r a n s f e r Q u e u e . j a v a : 1286 ) j a v a . b a s e @ 17 − l o o m / j a v a . u t i l . c o n c u r r e n t . E x e c u t o r S e r v i c e H e l p e r Node.block(LinkedTransferQueue.java:470) java.base@17-loom/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3470) java.base@17-loom/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3441) java.base@17-loom/java.util.concurrent.LinkedTransferQueue.awaitMatch(LinkedTransferQueue.java:669) java.base@17-loom/java.util.concurrent.LinkedTransferQueue.xfer(LinkedTransferQueue.java:616) java.base@17-loom/java.util.concurrent.LinkedTransferQueue.take(LinkedTransferQueue.java:1286) java.base@17-loom/java.util.concurrent.ExecutorServiceHelper Node.block(LinkedTransferQueue.java:470)java.base@17loom/java.util.concurrent.ForkJoinPool.unmanagedBlock(ForkJoinPool.java:3470)java.base@17loom/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3441)java.base@17loom/java.util.concurrent.LinkedTransferQueue.awaitMatch(LinkedTransferQueue.java:669)java.base@17loom/java.util.concurrent.LinkedTransferQueue.xfer(LinkedTransferQueue.java:616)java.base@17loom/java.util.concurrent.LinkedTransferQueue.take(LinkedTransferQueue.java:1286)java.base@17loom/java.util.concurrent.ExecutorServiceHelperBlockingQueueSpliterator.tryAdvance(ExecutorServiceHelper.java:197)
java.base@17-loom/java.util.Spliterator.forEachRemaining(Spliterator.java:326)
java.base@17-loom/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
java.base@17-loom/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
java.base@17-loom/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:550)
java.base@17-loom/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
java.base@17-loom/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
java.base@17-loom/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
java.base@17-loom/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
app//com.github.hashjang.LoomThreadMain.retrieveURLs(LoomThreadMain.java:43)
app//com.github.hashjang.LoomThreadMain.main(LoomThreadMain.java:29)

“ForkJoinPool-1-worker-1” #25
java.base@17-loom/jdk.internal.misc.Unsafe.park(Native Method)
java.base@17-loom/java.util.concurrent.locks.LockSupport.parkUntil(LockSupport.java:449)
java.base@17-loom/java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1719)
java.base@17-loom/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1616)
java.base@17-loom/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

“Read-Poller” #41
java.base@17-loom/sun.nio.ch.WEPoll.wait(Native Method)
java.base@17-loom/sun.nio.ch.WEPollPoller.poll(WEPollPoller.java:64)
java.base@17-loom/sun.nio.ch.Poller.poll(Poller.java:196)
java.base@17-loom/sun.nio.ch.Poller.lambda$startPollerThread 0 ( P o l l e r . j a v a : 66 ) j a v a . b a s e @ 17 − l o o m / s u n . n i o . c h . P o l l e r 0(Poller.java:66) java.base@17-loom/sun.nio.ch.Poller 0(Poller.java:66)java.base@17loom/sun.nio.ch.Poller$Lambda$89/0x00000008010e5168.run(Unknown Source)
java.base@17-loom/java.lang.Thread.run(Thread.java:1521)
java.base@17-loom/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:161)

“” #24 virtual
java.base/java.lang.Continuation.yield(Continuation.java:402)
java.base/java.lang.VirtualThread.yieldContinuation(VirtualThread.java:367)
java.base/java.lang.VirtualThread.park(VirtualThread.java:534)
java.base/java.lang.System 2. p a r k V i r t u a l T h r e a d ( S y s t e m . j a v a : 2373 ) j a v a . b a s e / j d k . i n t e r n a l . m i s c . V i r t u a l T h r e a d s . p a r k ( V i r t u a l T h r e a d s . j a v a : 60 ) j a v a . b a s e / s u n . n i o . c h . N i o S o c k e t I m p l . p a r k ( N i o S o c k e t I m p l . j a v a : 184 ) j a v a . b a s e / s u n . n i o . c h . N i o S o c k e t I m p l . p a r k ( N i o S o c k e t I m p l . j a v a : 212 ) j a v a . b a s e / s u n . n i o . c h . N i o S o c k e t I m p l . c o n n e c t ( N i o S o c k e t I m p l . j a v a : 607 ) j a v a . b a s e / j a v a . n e t . S o c k s S o c k e t I m p l . c o n n e c t ( S o c k s S o c k e t I m p l . j a v a : 331 ) j a v a . b a s e / j a v a . n e t . S o c k e t . c o n n e c t ( S o c k e t . j a v a : 642 ) j a v a . b a s e / s u n . s e c u r i t y . s s l . S S L S o c k e t I m p l . c o n n e c t ( S S L S o c k e t I m p l . j a v a : 299 ) j a v a . b a s e / s u n . s e c u r i t y . s s l . B a s e S S L S o c k e t I m p l . c o n n e c t ( B a s e S S L S o c k e t I m p l . j a v a : 174 ) j a v a . b a s e / s u n . n e t . N e t w o r k C l i e n t . d o C o n n e c t ( N e t w o r k C l i e n t . j a v a : 182 ) j a v a . b a s e / s u n . n e t . w w w . h t t p . H t t p C l i e n t . o p e n S e r v e r ( H t t p C l i e n t . j a v a : 497 ) j a v a . b a s e / s u n . n e t . w w w . h t t p . H t t p C l i e n t . o p e n S e r v e r ( H t t p C l i e n t . j a v a : 600 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p s . H t t p s C l i e n t . < i n i t > ( H t t p s C l i e n t . j a v a : 266 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p s . H t t p s C l i e n t . N e w ( H t t p s C l i e n t . j a v a : 380 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p s . A b s t r a c t D e l e g a t e H t t p s U R L C o n n e c t i o n . g e t N e w H t t p C l i e n t ( A b s t r a c t D e l e g a t e H t t p s U R L C o n n e c t i o n . j a v a : 189 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p . H t t p U R L C o n n e c t i o n . p l a i n C o n n e c t 0 ( H t t p U R L C o n n e c t i o n . j a v a : 1232 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p . H t t p U R L C o n n e c t i o n . p l a i n C o n n e c t ( H t t p U R L C o n n e c t i o n . j a v a : 1120 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p s . A b s t r a c t D e l e g a t e H t t p s U R L C o n n e c t i o n . c o n n e c t ( A b s t r a c t D e l e g a t e H t t p s U R L C o n n e c t i o n . j a v a : 175 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p . H t t p U R L C o n n e c t i o n . g e t I n p u t S t r e a m 0 ( H t t p U R L C o n n e c t i o n . j a v a : 1653 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p . H t t p U R L C o n n e c t i o n . g e t I n p u t S t r e a m ( H t t p U R L C o n n e c t i o n . j a v a : 1577 ) j a v a . b a s e / s u n . n e t . w w w . p r o t o c o l . h t t p s . H t t p s U R L C o n n e c t i o n I m p l . g e t I n p u t S t r e a m ( H t t p s U R L C o n n e c t i o n I m p l . j a v a : 224 ) j a v a . b a s e / j a v a . n e t . U R L . o p e n S t r e a m ( U R L . j a v a : 1159 ) c o m . g i t h u b . h a s h j a n g . L o o m T h r e a d M a i n . g e t U R L ( L o o m T h r e a d M a i n . j a v a : 48 ) c o m . g i t h u b . h a s h j a n g . L o o m T h r e a d M a i n . l a m b d a 2.parkVirtualThread(System.java:2373) java.base/jdk.internal.misc.VirtualThreads.park(VirtualThreads.java:60) java.base/sun.nio.ch.NioSocketImpl.park(NioSocketImpl.java:184) java.base/sun.nio.ch.NioSocketImpl.park(NioSocketImpl.java:212) java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:607) java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:331) java.base/java.net.Socket.connect(Socket.java:642) java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:299) java.base/sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:174) java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:182) java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:497) java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:600) java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:266) java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:380) java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:189) java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1232) java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1120) java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:175) java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1653) java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1577) java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224) java.base/java.net.URL.openStream(URL.java:1159) com.github.hashjang.LoomThreadMain.getURL(LoomThreadMain.java:48) com.github.hashjang.LoomThreadMain.lambda 2.parkVirtualThread(System.java:2373)java.base/jdk.internal.misc.VirtualThreads.park(VirtualThreads.java:60)java.base/sun.nio.ch.NioSocketImpl.park(NioSocketImpl.java:184)java.base/sun.nio.ch.NioSocketImpl.park(NioSocketImpl.java:212)java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:607)java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:331)java.base/java.net.Socket.connect(Socket.java:642)java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:299)java.base/sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:174)java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:182)java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:497)java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:600)java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:266)java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:380)java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:189)java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1232)java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1120)java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:175)java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1653)java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1577)java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224)java.base/java.net.URL.openStream(URL.java:1159)com.github.hashjang.LoomThreadMain.getURL(LoomThreadMain.java:48)com.github.hashjang.LoomThreadMain.lambdaretrieveURLs 0 ( L o o m T h r e a d M a i n . j a v a : 38 ) j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . F u t u r e T a s k . r u n ( F u t u r e T a s k . j a v a : 295 ) j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . T h r e a d E x e c u t o r 0(LoomThreadMain.java:38) java.base/java.util.concurrent.FutureTask.run(FutureTask.java:295) java.base/java.util.concurrent.ThreadExecutor 0(LoomThreadMain.java:38)java.base/java.util.concurrent.FutureTask.run(FutureTask.java:295)java.base/java.util.concurrent.ThreadExecutorTaskRunner.run(ThreadExecutor.java:385)
java.base/java.lang.VirtualThread.run(VirtualThread.java:295)
java.base/java.lang.VirtualThread V T h r e a d C o n t i n u a t i o n . l a m b d a VThreadContinuation.lambda VThreadContinuation.lambdanew$0(VirtualThread.java:172)
java.base/java.lang.Continuation.enter0(Continuation.java:372)
java.base/java.lang.Continuation.enter(Continuation.java:365)

通过这里的线程堆栈可以看出,虚拟线程在执行 I/O 操作的时候,会调用 java.lang.Continuation.yield 让出承载线程的资源(相当于 park 住了)。查看原来的承载线程 “ForkJoinPool-1-worker-1” #25,确实处于空闲状态了。那么 I/O 操作去哪里了呢?这就引出了这个线程 “Read-Poller” #41。

这个线程是一个 JVM 共用的 read poller。它的核心逻辑是执行一个基本事件循环,监听所有的同步网络 read(网络读就绪),connect(发起网络连接就绪) 和 accept(接受网络连接就绪) 操作。当这些 I/O 操作就绪的时候,poller 会被通知,并且 unpark 对应的虚拟线程,使得虚拟线程继续执行。同时,除了 read poller,还有一个用于写事件的 write poller。

我是使用 Windows 进行测试的,在 Windows 中 poller
底层实现基于 wepoll,所以我们看到堆栈里面包含 WEPoll。对于 MacOS 则是 kqueue,对于 Linux 则是 epoll

poller 维护一个以虚拟线程的文件描述符为 key 的 map。当一个虚拟线程并将它的文件描述符注册到 poller 上的时候,会以虚拟线程的文件描述符为 key,虚拟线程本身为 value 放入这个 map。当 poller 的事件循环中的相关事件就绪的时候,通过事件中的虚拟线程文件描述符在 map 中找到对应的虚拟线程 unpark 之。

伸缩扩展性
如果简单来看,上面的设计与使用 NIO Channel 和 Selector 并没有太大的不同,NIO Channel 和 Selector 可以在许多服务器端框架和库中找到,例如 Netty。但是相对来说,NIO Channel 和 Selector 提供了一个更复杂的模型,用户代码必须实现事件循环并跨 I/O 边界维护应用程序逻辑,而虚拟线程则提供了一个更简单、更直观的编程模型,Java 平台负责跨 I/O 边界调度任务和维护对应的上下文。

如前文我们看到的那样,虚拟线程默认的承载线程就是 ForkJoinPool。这是一个非常适合虚拟线程的线程池,工作窃取算法能极致的调度运行虚拟线程。
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值