Fundamentals 15 min read

Understanding Threads, Multithreading, and Virtual Threads in Java

This article explains the concept of threads in computer science, demonstrates how Java encapsulates threads with the Thread class, shows basic and multithreaded examples, introduces thread pools and their management, and details the new virtual thread model introduced by Project Loom for high‑throughput, low‑overhead concurrency.

政采云技术
政采云技术
政采云技术
Understanding Threads, Multithreading, and Virtual Threads in Java

Thread

In computer science, a thread (English: thread) is a unit of execution within a process, allowing concurrent execution on single‑processor, multi‑processor, or multi‑core systems.

Java Threads

All Java code runs on a single thread by default. The Thread class encapsulates Java threads; creating a new Thread instance starts a new thread of execution.

public static void main(String[] args) {
  Thread thread = new Thread(() -> {
    while (true) {
      System.out.println("Hello, World!");
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
        Thread.currentThread().interrupt();
      }
    }
  });
  thread.start();
}

The above code creates and starts a thread that prints "Hello, World!" every second.

Multithreading

Multithreading means running multiple threads simultaneously, which improves CPU utilization and system throughput, especially on multi‑core CPUs.

Java Multithreading

In Java, multithreading is achieved by creating multiple Thread objects.

public static void main(String[] args) {
  Thread thread1 = new Thread(() -> {
    System.out.println("Hello, World from thread " + Thread.currentThread().getName());
  });
  Thread thread2 = new Thread(() -> {
    System.out.println("Hello, World from thread " + Thread.currentThread().getName());
  });
  thread1.start();
  thread2.start();
}

Output order varies because thread scheduling is nondeterministic.

Thread Pools

Thread‑pooling prepares reusable resources to avoid the overhead of creating and destroying threads repeatedly. Java’s ExecutorService hierarchy (e.g., Executors.newFixedThreadPool ) provides pooled thread management.

public static void main(String[] args) {
  try (ExecutorService executorService = Executors.newFixedThreadPool(10)) {
    IntStream.range(0, 100).forEach(i -> executorService.submit(() -> {
      System.out.println(Thread.currentThread().getName() + " " + i);
    }));
  }
}

Creating too many platform threads (e.g., 10,000) can cause OutOfMemoryError: unable to create native thread and degrade performance due to excessive context switching.

Virtual Threads

Virtual threads, introduced by Project Loom (JEP 425), decouple Java threads from OS threads, allowing millions of lightweight threads to be scheduled on a few platform threads. They are created with Thread.ofVirtual() or Thread.startVirtualThread() and share the same API as platform threads.

public static void main(String[] args) {
  Thread virtualThread1 = Thread.ofVirtual().start(() -> System.out.println("Hello, World!"));
  Thread virtualThread2 = Thread.startVirtualThread(() -> System.out.println("Hello, World!"));
  try {
    Thread.startVirtualThread(() -> {
      try { Thread.sleep(3000); }
      catch (InterruptedException e) { Thread.currentThread().interrupt(); }
      System.out.println("Hello, World!");
    }).join(0);
  } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}

Virtual threads are cheap to create and should not be pooled; they are typically discarded after use.

Virtual Thread Scheduler

The scheduler creates a new virtual thread for each submitted task. Example using Executors.newVirtualThreadPerTaskExecutor() :

public static void main(String[] args) {
  ExecutorService executorService1 = Executors.newVirtualThreadPerTaskExecutor();
  try (ExecutorService executorService2 = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 100000).forEach(i -> executorService2.submit(() -> {
      try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); }
      System.out.println("Hello from " + Thread.currentThread());
    }));
  }
}

Virtual threads run on a ForkJoinPool; the parallelism can be tuned via jdk.virtualThreadScheduler.parallelism .

Debugging Virtual Threads

Standard breakpoint debugging works as with platform threads. Thread dumps can be generated in JSON format using:

jcmd
Thread.dump_to_file -format=json

Thread‑Local Variables

Both platform and virtual threads support ThreadLocal and InheritableThreadLocal , but excessive use in virtual threads should be avoided. Scoped Values (JEP 429) are the recommended alternative.

References

https://zh.wikipedia.org/zh-hans/线程

https://openjdk.org/jeps/425

https://openjdk.org/jeps/444

https://openjdk.org/jeps/429

JavaConcurrencyJDKthread poolVirtual ThreadsThreads
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.