Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The easiest way to get started is to configure your IDE to use a recent Project Loom JDK 19 Early Access (EA) build and get familiar with using the java.lang.Thread API to create a virtual thread to execute some code. Virtual threads are just threads that are scheduled by the Java virtual machine JDK rather than the operating system. Virtual threads are best suited to executing code that spends most of its time blocked, waiting for a data to arrive on a network socket or waiting for an element in queue for example.

Many applications won't use the Thread API directly but instead will use the java.util.concurrent.ExecutorService and Executors APIs. The Executors API has been updated with new factory methods for ExecutorServices that start a new thread for each task. Virtual threads are cheap enough that a new virtual thread can be created for each task, there should never be a need to pool virtual threads.

Thread API

The following uses a static factory method to start a virtual thread. It invokes starts a virtual thread to print a message.  It invokes the join method to wait for the thread to terminate.

Code Block
languagejava
Thread thread = Thread.ofVirtual().startVirtualThreadstart(() -> System.out.println("Hello"));
thread.join();

...

The following is an example that creates start a virtual thread that puts to put an element into a queue when it has completed a taskafter sleeping. The main thread blocks on the queue, waiting for the element.

Code Block
languagejava
        var queue = new SynchronousQueue<String>();

        Thread.startVirtualThreadofVirtual().start(() -> {
            try {
                Thread.sleep(Duration.ofSeconds(2));
                queue.put("done");
            } catch (InterruptedException e) { }
        });

        String msg = queue.take();

The Thread.Builder API can also be used to create virtual threads. The following has two code snippets. The first creates an un-started thread. The second creates and starts a thread with name "bob".

Code Block
languagejava
Thread thread1 = Thread.ofVirtual().unstarted(() -> System.out.println("Hello"));

Thread thread2 = Thread.ofVirtual().name("bob").start(() -> System.out.println("I'm Bob!"))


The Thread.Builder API can also be used to create a ThreadFactory. The ThreadFactory created by the following snippet will create virtual threads named "worker-0", "worker-1", "worker-2", ...

...

Code Block
languagejava
        try (ExecutorService executor = Executors.newVirtualThreadExecutor()) {

            // Submits a value-returning task and waits for the result
            Future<String> future = executor.submit(() -> "foo");
            String result = future.join();

            // Submits two value-returning tasks to get a Stream that is lazily populated
            // with completed Future objects as the tasks complete
            Stream<Future<String>> stream = executor.submit(List.of(() -> "foo", () -> "bar"));
            stream.filter(Future::isCompletedNormally)
                    .map(Future::join)
                    .forEach(System.out::println);

            // Executes two value-returning tasks, waiting for both to complete
            List<Future<String>> results1 = executor.invokeAll(List.of(() -> "foo", () -> "bar"));

            // Executes two value-returning tasks, waiting for both to complete. If one of the
            // tasks completes with an exception, the other is cancelled.
            List<Future<String>> results2 = executor.invokeAll(List.of(() -> "foo", () -> "bar"), /*cancelOnExceptionwaitAll*/ truefalse);

            // Executes two value-returning tasks, returning the result of the first to
            // complete, cancelling the other.
            String first = executor.invokeAny(List.of(() -> "foo", () -> "bar"));

        }

...