1 # Custom Schedulers
 2 
 3 The following is a summary of the experimental support for custom virtual thread schedulers
 4 in the loom repo.
 5 
 6 The purpose of the experimental support is to allow exploration and provide feedback to help
 7 inform the project on whether to expose anything.
 8 
 9 
10 
11 ## Using a custom scheduler as the default scheduler
12 
13 The default virtual thread scheduler is selected when starting a new virtual thread with
14 `Thread.startVirtualThread`, or creating a virtual thread with the `Thread.Builder` API and
15 not specifying a scheduler The default scheduler is a `ForkJoinPool` instance that is
16 configured in FIFO mode.  A different default scheduler can be used by setting a system
17 property on the command line.
18 
19 ```
20 -Djdk.virtualThreadScheduler.implClass=$EXECUTOR
21 ```
22 
23 where $EXECUTOR is fully qualified name of a class that implements `java.util.concurrent.Executor`.
24 
25 The class must be public, with a public no-arg constructor, and deployed on the class path
26 or in an exported package of a module on the module path.
27 
28 The scheduler's `execute` method will be invoked with tasks of type `Thread.VirtualThreadTask`.
29 The scheduler must arrange to execute the tasks on a platform thread,.
30 
31 
32 
33 ## Selecting a custom scheduler when creating a virtual thread
34 
35 `Thread.Builder.OfVirtual.scheduler(Executor)` can be used to set the scheduler when creating
36 a virtual thread. The following uses a thread pool with 8 threads as the scheduler.
37 
38 ```
39 ExecuorService pool = Executors.newFixedThreadPool(8);
40 
41 Thread thread = Thread.ofVirtual().scheduler(pool).start(() -> { });
42 thread.join();
43 ```
44 
45 As with a custom default scheduler, the scheduler's `execute` method will be invoked with
46 tasks of type `Thread.VirtualThreadTask`. The scheduler must arrange to execute the tasks o
47 n a platform thread.
48 
49 
50 
51 ## Thread.VirtualThreadTask
52 
53 A custom scheduler can cast the `Runnable` task to `Thread.VirtualThreadTask`.  This allows
54 the scheduler to know which virtual thread needs to execute. It also allows the scheduler
55 to attach arbitrary context. The following is an example uses an attached object to give
56 the mounted virtual thread a reference to is carrier thread, and to the scheduler.
57 
58 ```
59 record Context(Executor scheduler, Thread carrier) { }
60 
61 @Override
62 public void execute(Runnable task) {
63     pool.submit(() -> {
64         var vthreadTask = (Thread.VirtualThreadTask) task;
65         vthreadTask.attach(new Context(this, Thread.currentThread()));
66         try {
67             vthreadTask.run();
68         } finally {
69             vthreadTask.attach(null);
70         }
71     });
72 }
73 
74 Thread.ofVirtual()
75       .scheduler(customScheduler)
76       .start(() -> {
77 
78           if (Thread.VirtualThreadTask.currentVirtualThreadTaskAttachment()
79                   instanceof Context ctxt) {
80               Executor scheduler = ctxt.scheduler();
81               Thread carrier = ctxt.carrier();
82           }
83 
84       });
85 ```
86 
87 
88 
89 
90 
91 
92