You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: app/pages/learn/01_tutorial/02_new-features/00_virtual-threads.md
+33-18Lines changed: 33 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,19 +1,27 @@
1
1
---
2
2
id: new_features.virtual_threads
3
3
title: Virtual Threads
4
-
slug: learn/virtual-threads
4
+
slug: learn/new-features/virtual-threads
5
5
type: tutorial
6
6
category: awareness
7
-
category_order: 2
8
-
group: refactoring-to-functional-style
9
-
layout: learn/tutorial-group-top.html
7
+
category_order: 1
8
+
layout: learn/tutorial.html
10
9
main_css_id: learn
11
10
subheader_select: tutorials
11
+
toc:
12
+
- Why Virtual Threads? {why}
13
+
- Creating Virtual Threads {creating}
14
+
- Thread API Changes {api-changes}
15
+
- Capturing Task Results {task-results}
16
+
- Rate Limiting {rate-limiting}
17
+
- Pinning {pinning}
18
+
- Thread Locals {thread-locals}
19
+
- Conclusion {conclusion}
12
20
description: "Virtual Threads: What, Why, and How?"
13
21
author: ["CayHorstmann"]
14
22
---
15
23
16
-
24
+
<aid="why"> </a>
17
25
## Why Virtual Threads?
18
26
19
27
When Java 1.0 was released in 1995, its API had about a hundred classes, among them `java.lang.Thread`. Java was the first mainstream programming language that directly supported concurrent programming.
@@ -30,11 +38,12 @@ With virtual threads, blocking is cheap. When a result is not immediately availa
30
38
31
39
Virtual threads are useful when the number of concurrent tasks is large, and the tasks mostly block on network I/O. They offer no benefit for CPU-intensive tasks. For such tasks, consider parallel streams or [recursive fork-join tasks](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/RecursiveTask.html).
32
40
41
+
<aid="creating"> </a>
33
42
## Creating Virtual Threads
34
43
35
44
The factory method `Executors.newVirtualThreadPerTaskExecutor()` yields an `ExecutorService` that runs each task in a separate virtual thread. For example:
36
45
37
-
```
46
+
```java
38
47
importjava.util.concurrent.*;
39
48
40
49
publicclassVirtualThreadDemo {
@@ -57,7 +66,7 @@ By the way, the code uses `LockSupport.parkNanos` instead of `Thread.sleep` so t
57
66
58
67
Perhaps you are using a lower-level API that asks for a thread factory. To obtain a factory for virtual threads, use the new `Thread.Builder` class:
@@ -66,24 +75,25 @@ Now, calling `factory.newThread(myRunnable)` creates a new (unstarted) virtual t
66
75
67
76
You can also use a builder to create a single virtual thread:
68
77
69
-
```
78
+
```java
70
79
Thread t = builder.unstarted(myRunnable);
71
80
```
72
81
73
82
Alternatively, if you want to start the thread right away:
74
83
75
-
```
84
+
```java
76
85
Thread t = builder.started(myRunnable);
77
86
```
78
87
79
88
Finally, for a quick demo, there is a convenience method:
80
89
81
-
```
90
+
```java
82
91
Thread t =Thread.startVirtualThread(myRunnable);
83
92
```
84
93
85
94
Note that only the first approach, with an executor service, works with result-bearing tasks (callables).
86
95
96
+
<aid="api-changes"> </a>
87
97
## Thread API Changes
88
98
89
99
After a series of experiments with different APIs, the designers of Java virtual threads decided to simply reuse the familiar `Thread` API. A virtual thread is an instance of `Thread`. Cancellation works the same way as for platform threads, by calling `interrupt`. As always, the thread code must check the “interrupted” flag or call a method that does. (Most blocking methods do.)
@@ -109,19 +119,20 @@ Java 19 has a couple of changes to the `Thread` API that have nothing to do with
109
119
110
120
As of Java 20, the `stop`, `suspend`, and `resume` methods throw an `UnsupportedOperationException` for both platform and virtual threads. These methods have been deprecated since Java 1.2 and deprecated for removal since Java 18.
111
121
122
+
<aid="task-results"> </a>
112
123
## Capturing Task Results
113
124
114
125
You often want to combine the results of multiple concurrent tasks:
115
126
116
-
```
127
+
```java
117
128
Future<T1> f1 = service.submit(callable1);
118
129
Future<T2> f2 = service.submit(callable2);
119
130
result = combine(f1.get(), f2.get());
120
131
```
121
132
122
133
Before virtual threads, you might have felt bad about the blocking `get` calls. But now blocking is cheap. Here is a sample program with a more concrete example:
123
134
124
-
```
135
+
```java
125
136
importjava.util.concurrent.*;
126
137
importjava.net.*;
127
138
importjava.net.http.*;
@@ -153,7 +164,7 @@ public class VirtualThreadDemo {
153
164
154
165
If you have a list of tasks with the same result type, you can use the `invokeAll` method and then call `get` on each `Future`:
155
166
156
-
```
167
+
```java
157
168
List<Callable<T>> callables =...;
158
169
List<T> results =newArrayList<>();
159
170
for (Future<T> f : service.invokeAll(callables))
@@ -162,7 +173,7 @@ for (Future<T> f : service.invokeAll(callables))
162
173
163
174
Again, a more concrete sample program:
164
175
165
-
```
176
+
```java
166
177
importjava.util.*;
167
178
importjava.util.concurrent.*;
168
179
importjava.net.*;
@@ -198,6 +209,7 @@ public class VirtualThreadDemo {
198
209
}
199
210
```
200
211
212
+
<aid="rate-limiting"> </a>
201
213
## Rate Limiting
202
214
203
215
Virtual threads improve application throughput since you can have many more concurrent tasks than with platform threads. That can put pressure on the services that the tasks invoke. For example, a web service may not tolerate huge numbers of concurrent requests.
@@ -210,7 +222,7 @@ As an example, on my personal web site, I provide demo services for producing ra
210
222
211
223
The following sample program shows rate limiting with a simple semaphore that allows a small number of concurrent requests. When the maximum is exceeded, the `acquire` method blocks, but that is ok. With virtual threads, blocking is cheap.
212
224
213
-
```
225
+
```java
214
226
importjava.util.*;
215
227
importjava.util.concurrent.*;
216
228
importjava.net.*;
@@ -253,6 +265,7 @@ public class RateLimitDemo {
253
265
}
254
266
```
255
267
268
+
<aid="pinning"> </a>
256
269
## Pinning
257
270
258
271
The virtual thread scheduler mounts virtual threads onto carrier threads. By default, there are as many carrier threads as there are CPU cores. You can tune that count with the `jdk.virtualThreadScheduler.parallelism` VM option.
@@ -272,14 +285,14 @@ You always have the option whether or not to use virtual threads. In particular,
272
285
273
286
To find out whether pinned threads are blocked, start the JVM with one of the options
274
287
275
-
```
288
+
```shell
276
289
-Djdk.tracePinnedThreads=short
277
290
-Djdk.tracePinnedThreads=full
278
291
```
279
292
280
293
You get a stack trace that shows when a pinned thread blocks:
@@ -296,7 +309,7 @@ The following sample program shows pinning in action. We launch a number of virt
296
309
* use a `ReentrantLock`
297
310
* don't use virtual threads
298
311
299
-
```
312
+
```java
300
313
importjava.util.concurrent.*;
301
314
importjava.util.concurrent.locks.*;
302
315
@@ -344,6 +357,7 @@ public class PinningDemo {
344
357
}
345
358
```
346
359
360
+
<aid="thread-locals"> </a>
347
361
## Thread Locals
348
362
349
363
A *thread-local variable* is an object whose `get` and `set` methods access a value that depends on the current thread. Why would you want such a thing instead of using a global or local variable? The classic application is a service that is not threadsafe, such as `SimpleDateFormat`, or that would suffer from contention, such as a random number generator. In these cases, a per-thread shared instance makes sense.
@@ -356,6 +370,7 @@ An *inheritable thread-local variable* is a special kind of thread-local variabl
356
370
357
371
Such mutation is uncommon. Run with the VM flag `jdk.traceVirtualThreadLocals` to get a stack trace when a virtual thread mutates a thread-local variable.
358
372
373
+
<aid="conclusion"> </a>
359
374
## Conclusion
360
375
361
376
* Use virtual threads to increase throughput when you have many tasks that mostly block on network I/O
0 commit comments