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