Premise before a long period of attention JDKThe development progress of the coroutine library, but I was very busy for a period of time and rarely checked it OpenJDKThe content of the official website. Java coroutine projectLoom(Since the project is still in the development stage,OpenJDKOfficial website givenOpenjdk.java.net/projects/lo…Only a small amount ofLoomInformation related to the project) has been established prior to 2018 and has been published based onJDK17Compile and JDK18Compilation and other early versions of the author in the downloadLoomEarly versions of the time only foundJDK18Compiled version:Download from:jdk.java.net/loom

Because the JDK version is too high, you can use the mainstream IDE import Loom-JDK-18+9 for code highlighting and syntax reminding, temporarily can not find a way to compile, temporarily use the JDK to execute the directory under the javac command script to compile, use Java command script to run.

A brief introduction to Loom project

Loom - Fibers, Continuations and Tail-Calls for the JVM
Copy the code

The title of the Loom project already highlights three new features introduced:

  • Fibers: I saw it a few years agoLoom The project’s test code is used Fiberthis API(Now this oneAPIHas been removed), which stands for lightweight thread, also known as coroutine, also known as lightweight user thread, which is amazing at the momentJDKIs actually calledVirtual Thread
  • Continuations“What is the next block of code to be executed?”
  • Tail-CallsTail: call VMLevel of support

The three new features are not detailed. They are currently only EA versions and are subject to change, so there is no need to elaborate on them.

Virtual Thread using

Coroutine use in the current version of Loom project does not introduce a new public VirtualThread class. Although virtualThreads do exist, this class uses the default modifier and is hidden in the java.lang package. VirtualThread is a subclass of Thread. The coroutine creation API is in the Thread class:

Coroutine use in the current version of Loom project does not introduce a new public VirtualThread class. Although virtualThreads do exist, this class uses the default modifier and is hidden in the java.lang package. VirtualThread is a subclass of Thread. The coroutine creation API is in the Thread class:

Create coroutines using this API as follows:

public static void main(String[] args) {
    Thread fiber = Thread.startVirtualThread(() -> System.out.println("Hello Fiber"));
}
Copy the code

From the current source:

VirtualThread gets the parent Thread’s scheduler via Thread.currentThread(). If run in main, The parent thread of the coroutine instance in the code above is the ForkJoinPool instance (virtualThread.default_scheduler) created for the system by the default scheduler of the main thread. The input Runnable instance is encapsulated as a RunContinuation, and the scheduler ultimately executes the coroutine for timed unpark, Use the system to create instances of ScheduledExecutorService to wake up The static factory methods to create the coroutines running immediately, returns the coroutines instance If, in accordance with the above Thread. StartVirtualThread () method to create coroutines, Properties such as the name of the coroutine cannot obviously be defined. The Loom project solves this problem reasonably by introducing the Builder pattern for the Thread class:

// Create a platform Thread builder corresponding to the Thread instance
public static Builder.OfPlatform ofPlatform(a) {
    return new ThreadBuilders.PlatformThreadBuilder();
}

// create a VirtualThread builder corresponding to a VirtualThread
public static Builder.OfVirtual ofVirtual(a) {
    return new ThreadBuilders.VirtualThreadBuilder();
}
Copy the code

To put it simply:

The ofPlatform() method is used to create VirtualThread instances. The ofVirtual() method is used to create VirtualThread instances. The ofPlatform() method is used to create VirtualThread instances. The chain of all Setter methods for the two constructor instances is expanded as follows:

public static void main(String[] args) {
    Thread.Builder.OfPlatform platformThreadBuilder = Thread.ofPlatform()
            // Whether to daemon the thread
            .daemon(true)
            / / thread group
            .group(Thread.currentThread().getThreadGroup())
            // The thread name
            .name("thread-1")
            Prefix + (start + 1) => prefix + (start + 1) => prefix + (start + 1)
            // start > 0 overrides the name attribute configuration
            .name("thread-".1L)
            // Whether to enable ThreadLocal
            .allowSetThreadLocals(false)
            // Whether to enable InheritableThreadLocal
            .inheritInheritableThreadLocals(false)
            // Set the priority
            .priority(100)
            // Set the thread stack depth
            .stackSize(10)
            // Sets the exception handler not caught
            .uncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {

                }
            });
    // thread-1
    Thread firstThread = platformThreadBuilder.unstarted(() -> System.out.println("Hello Platform Thread First"));
    // thread-2
    Thread secondThread = platformThreadBuilder.unstarted(() -> System.out.println("Hello Platform Thread Second"));
    Thread.Builder.OfVirtual virtualThreadBuilder = Thread.ofVirtual()
            // Coroutine name
            .name("fiber-1")
            // Coroutine name prefix + start increment => prefix + start, the next coroutine name created is prefix + (start + 1)
            // start > 0 overrides the name attribute configuration
            .name("fiber-".1L)
            // Whether to enable ThreadLocal
            .allowSetThreadLocals(false)
            // Whether to enable InheritableThreadLocal
            .inheritInheritableThreadLocals(false)
            // Set the scheduler. Executor instances, where the scheduler is a thread pool, to NULL use VirtualThread.DEFAULT_SCHEDULER
            .scheduler(null)
            // Sets the exception handler not caught
            .uncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {

                }
            });
    // fiber-1
    Thread firstFiber = virtualThreadBuilder.unstarted(() -> System.out.println("Hello Platform Virtual First"));
    // fiber-2
    Thread secondFiber = virtualThreadBuilder.unstarted(() -> System.out.println("Hello Platform Virtual Second"));
}
Copy the code

One thing you can see here is that the builder is reusable. If you want to use the builder to create threads or coroutines with the same set of parameters, you can set the name(String prefix, long start) method to define the thread or coroutine name prefix with a number greater than or equal to zero. To batch create threads or coroutines, call Builder#unstarted(Runnable task) repeatedly. Set the name to prefix + start, prefix + (start + 1), prefix + (start + 2), and so on. Coroutine creation is basically as simple as that, calling the start() method directly to run it:

public class FiberSample2 {

    public static void main(String[] args) throws Exception {
        Thread.ofVirtual()
                .name("fiber-1")
                .allowSetThreadLocals(false)
                .inheritInheritableThreadLocals(false)
                .unstarted(() -> {
                    Thread fiber = Thread.currentThread();
                    System.out.printf("[%s,daemon:%s,virtual:%s] - Hello World\n", fiber.getName(),
                            fiber.isDaemon(), fiber.isVirtual());
                }).start();
        // The main thread is asleepThread.sleep(Long.MAX_VALUE); }}Copy the code

Currently, the above classes cannot be compiled in mainstream IDES, so you can only compile and run them using tools in the JDK directory as follows:

I:\ j-projects \framework-source-code\fiber-sample\ SRC \main\ Java (1I: Environment\Java\ JDK18-loom\bin\javac.exe I:\J-Projects\framework-source-code\fiber-sample\src\main\java\cn\throwx\fiber\sample\FiberSample2.java
(2Execute the main method: I: Environment\Java\ JDK18-loom\bin\java.exe  cn.throwx.fiber.sample.FiberSample2
Copy the code

One thing you see here, too, is that for all instances of coroutines daemonFlag defaults totrueIt cannot be modified. ## Summary if use the Angle of taste to useLoomProjects can be snooped in advanceJVMHow are developers building on this significant feature of coroutines to improve learningJDKAn interest in kernel code helps a lot. For now, the implementation of coroutines LoomProject distanceRELEASEVersion of the estimated many functions need to be improved, including newAPIAnd whether coroutines can be ported to the originalJUCUsed in the class libraryLoom-JDK-18+9There are no changes to the original thread pool, etc.), so wait while you keep your eyes open.