接下来编写代码:
//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@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.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@17−loom/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)java.base@17−loom/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@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.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@17−loom/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