Skip to content

Commit 17b544e

Browse files
committed
Fixed: syntax coloring.
Fixed: table of content is not generated. Fixed: the page is not displayed on the learn page.
1 parent 5bb7ebe commit 17b544e

File tree

1 file changed

+33
-18
lines changed

1 file changed

+33
-18
lines changed

app/pages/learn/01_tutorial/02_new-features/virtual-threads.md renamed to app/pages/learn/01_tutorial/02_new-features/00_virtual-threads.md

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
---
22
id: new_features.virtual_threads
33
title: Virtual Threads
4-
slug: learn/virtual-threads
4+
slug: learn/new-features/virtual-threads
55
type: tutorial
66
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
109
main_css_id: learn
1110
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}
1220
description: "Virtual Threads: What, Why, and How?"
1321
author: ["CayHorstmann"]
1422
---
1523

16-
24+
<a id="why">&nbsp;</a>
1725
## Why Virtual Threads?
1826

1927
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
3038

3139
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).
3240

41+
<a id="creating">&nbsp;</a>
3342
## Creating Virtual Threads
3443

3544
The factory method `Executors.newVirtualThreadPerTaskExecutor()` yields an `ExecutorService` that runs each task in a separate virtual thread. For example:
3645

37-
```
46+
```java
3847
import java.util.concurrent.*;
3948

4049
public class VirtualThreadDemo {
@@ -57,7 +66,7 @@ By the way, the code uses `LockSupport.parkNanos` instead of `Thread.sleep` so t
5766

5867
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:
5968

60-
```
69+
```java
6170
Thread.Builder builder = Thread.ofVirtual().name("request-", 1);
6271
ThreadFactory factory = builder.factory();
6372
```
@@ -66,24 +75,25 @@ Now, calling `factory.newThread(myRunnable)` creates a new (unstarted) virtual t
6675

6776
You can also use a builder to create a single virtual thread:
6877

69-
```
78+
```java
7079
Thread t = builder.unstarted(myRunnable);
7180
```
7281

7382
Alternatively, if you want to start the thread right away:
7483

75-
```
84+
```java
7685
Thread t = builder.started(myRunnable);
7786
```
7887

7988
Finally, for a quick demo, there is a convenience method:
8089

81-
```
90+
```java
8291
Thread t = Thread.startVirtualThread(myRunnable);
8392
```
8493

8594
Note that only the first approach, with an executor service, works with result-bearing tasks (callables).
8695

96+
<a id="api-changes">&nbsp;</a>
8797
## Thread API Changes
8898

8999
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
109119

110120
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.
111121

122+
<a id="task-results">&nbsp;</a>
112123
## Capturing Task Results
113124

114125
You often want to combine the results of multiple concurrent tasks:
115126

116-
```
127+
```java
117128
Future<T1> f1 = service.submit(callable1);
118129
Future<T2> f2 = service.submit(callable2);
119130
result = combine(f1.get(), f2.get());
120131
```
121132

122133
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:
123134

124-
```
135+
```java
125136
import java.util.concurrent.*;
126137
import java.net.*;
127138
import java.net.http.*;
@@ -153,7 +164,7 @@ public class VirtualThreadDemo {
153164

154165
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`:
155166

156-
```
167+
```java
157168
List<Callable<T>> callables = ...;
158169
List<T> results = new ArrayList<>();
159170
for (Future<T> f : service.invokeAll(callables))
@@ -162,7 +173,7 @@ for (Future<T> f : service.invokeAll(callables))
162173

163174
Again, a more concrete sample program:
164175

165-
```
176+
```java
166177
import java.util.*;
167178
import java.util.concurrent.*;
168179
import java.net.*;
@@ -198,6 +209,7 @@ public class VirtualThreadDemo {
198209
}
199210
```
200211

212+
<a id="rate-limiting">&nbsp;</a>
201213
## Rate Limiting
202214

203215
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
210222

211223
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.
212224

213-
```
225+
```java
214226
import java.util.*;
215227
import java.util.concurrent.*;
216228
import java.net.*;
@@ -253,6 +265,7 @@ public class RateLimitDemo {
253265
}
254266
```
255267

268+
<a id="pinning">&nbsp;</a>
256269
## Pinning
257270

258271
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,
272285

273286
To find out whether pinned threads are blocked, start the JVM with one of the options
274287

275-
```
288+
```shell
276289
-Djdk.tracePinnedThreads=short
277290
-Djdk.tracePinnedThreads=full
278291
```
279292

280293
You get a stack trace that shows when a pinned thread blocks:
281294

282-
```
295+
```shell
283296
...
284297
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) <== monitors:1
285298
...
@@ -296,7 +309,7 @@ The following sample program shows pinning in action. We launch a number of virt
296309
* use a `ReentrantLock`
297310
* don't use virtual threads
298311

299-
```
312+
```java
300313
import java.util.concurrent.*;
301314
import java.util.concurrent.locks.*;
302315

@@ -344,6 +357,7 @@ public class PinningDemo {
344357
}
345358
```
346359

360+
<a id="thread-locals">&nbsp;</a>
347361
## Thread Locals
348362

349363
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
356370

357371
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.
358372

373+
<a id="conclusion">&nbsp;</a>
359374
## Conclusion
360375

361376
* Use virtual threads to increase throughput when you have many tasks that mostly block on network I/O

0 commit comments

Comments
 (0)