1 # Custom Schedulers
 2 
 3 The following is a summary of the experimental support for custom virtual thread schedulers
 4 in the `fibers` branch of the loom repo.
 5 
 6 The purpose of the experimental support is to allow exploration and get feedback to help
 7 inform this project on whether to expose anything.
 8 
 9 The experimental support may change or be removed at any time.
10 
11 ## Using a custom scheduler as the virtual thread scheduler
12 
13 The JDK's built-in virtual thread scheduler is a `ForkJoinPool` instance that is
14 configured in FIFO mode.
15 
16 The virtual thread scheduler can be configured to be a custom scheduler by setting
17 a system property on the command line:
18 
19 
20 ```
21 -Djdk.virtualThreadScheduler.implClass=<scheduler-class>
22 ```
23 
24 where `<scheduler-class>` is fully qualified name of a class that implements
25 `java.lang.Thread.VirtualThreadScheduler`.
26 
27 The custom scheduler may use its own pool of platform threads, may assign virtual threads
28 to be carried by specific platform threads, or may delegate to the built-in virtual thread
29 scheduler.
30 
31 The implementation class must be public, with a public no-arg or one-arg constructor, and
32 deployed on the class path or in an exported package of a module on the module path. If the
33 class has a one-arg constructor then the parameter is a `java.lang.Thread.VirtualThreadScheduler`
34 that is a reference to the built-in scheduler (this allows the custom scheduler
35 to delegate to the built-in scheduler if required).
36 
37 
38 ## API to select a custom scheduler when creating a virtual thread
39 
40 The `Thread.Builder.OfVirtual.scheduler(Thread.VirtualThreadScheduler)` API can be used
41 to set the scheduler when creating a virtual thread. The following example uses a thread
42 pool with 8 threads as the scheduler.
43 
44 ```
45 ExecuorService pool = Executors.newFixedThreadPool(8);
46 var scheduler = Thread.VirtualThreadScheduler.adapt(pool);
47 
48 Thread thread = Thread.ofVirtual().scheduler(scheduler).start(() -> { });
49 thread.join();
50 ```
51 
52 The prototype API allows different parts of a system to use different schedulers.
53 
54 Custom schedulers are _not inherited_. If a virtual thread assigned to a custom
55 scheduler invokes `Thread.startVirtualThread(Runnable)` then it starts a virtual
56 thread assigned to the default scheduler.
57 
58 Custom schedulers are _not closable_. They are managed by the garbage collector so that
59 a custom scheduler can be collected when all virtual thread assigned to the scheduler
60 have terminated and the scheduler is otherwise unreachable. The lifecycle of carrier
61 threads is managed by the scheduler.
62 
63 ## Poller modes
64 
65 Socket I/O in the context of virtual threads uses a platform specific I/O event notification
66 facility such as `kqueue`, `epoll`, or `io_uring`. The implementation uses of set of internal
67 _poller threads_ that consume events from the I/O event notification facility to unpark
68 virtual threads that are blocked in socket operations. The implementation has a number
69 of _poller modes_. On macOS and Windows there is a set of platform threads that wait for
70 events. On Linux, the poller threads that consume the events from the I/O event notification
71 facility are virtual threads assigned to the default scheduler.
72 
73 When using a custom scheduler it may be useful to use the poller mode that creates an I/O
74 event notification system and a poller virtual thread per carrier thread. The poller
75 thread terminates if the carrier terminates; any outstanding socket I/O operations
76 are moved to a different carrier's I/O event notification facility. This poller mode is
77 currently implemented on Linux and macOS and is used when running with `-Djdk.pollerMode=3`.