The labs on this site need JavaScript to run. The same content is written out below.
Fundamentals › Java
What is a thread, and what does start() do?
A thread is one flow of execution that runs code from top to bottom. A Java program starts with one thread named main, and this thread runs the main method from the top. The part of the code that creates a thread object is new Thread(() -> work()). The () -> work() in the parentheses is code that says "call work()" and is handed to the new flow. This line only creates a Thread object and does not create a new flow. When you call t.start(), a new flow is created at that moment, and the new thread runs the code that was handed to it. t.join() makes main wait until that thread finishes, and Thread.currentThread().getName() tells you the name of the thread that is running this line right now. In this lab you replace the start() line with a call to run() or remove it, and create one more thread, and the same code is compiled and run to show the name of the thread that ran work and the last line, and the number of newly started threads. (What happens when two flows move at the same time is not covered. You only see the shape in which join makes main wait, so the order of the output is fixed.)
Checked against real execution · Compiled 6 combinations with javax.tools on JDK 21, ran each 20 times as a child java process, and checked the output and the number of newly started threads
public class Main {
static void work() {
String who = Thread.currentThread().getName();
System.out.println("Thread that ran work: " + who);
}
public static void main(String[] args) throws Exception {
// Create a thread object. No new flow exists yet
Thread t = new Thread(() -> work());
// start: a new flow is created and runs work
t.start();
// join: main waits until that thread finishes
t.join();
String me = Thread.currentThread().getName();
System.out.println("Thread that ran this line: " + me);
}
}
The compiler and runtime are JDK 21.0.12.1 (javac 21). All 6 combinations were checked against real runs: the same source as the code on the screen (identical line by line) was compiled with javax.tools, and the java of this JDK was started as a child process and actually run 20 times for each combination. In all 120 runs the exit code was 0 and the standard error was empty, and for each combination the standard output was the same in all 20 runs. What was checked is the lines of the standard output (the Output column of the result table), the names of the threads that appear in those lines (the Thread that ran work column), and the number of newly started threads. The number of newly started threads was measured without changing the source on the screen: the start class of the child process read ThreadMXBean.getTotalStartedThreadCount() before and after it called Main.main, and the difference was used (the combinations that call start gave 1 and 2, and the others gave 0, the same in all 20 runs). The facts that the step sentences rely on were checked by running a separately written source 20 times in the same way. Right after a Thread object is created its state is NEW and isAlive() is false, after start() the new thread and main are both alive (the new thread was held in the WAITING state), and after join() returns the state is TERMINATED. When run() is called, main runs the handed code, and even after the call the state of that Thread object is still NEW, and join() of a thread that was never started returns right away without waiting. For the documentation, I opened java.lang.Thread in the Java SE 21 API documentation with WebFetch (I followed the sentences that the excerpts returned and did not read the whole page myself). That a thread is a flow of execution and, once started, is scheduled to run the run method follows the class description; that threads created with Thread() and Thread(Runnable), which are not given a name, are automatically given a name made of "Thread-" and an integer follows the constructor description; that start() schedules the execution of a new thread and it runs separately from the current thread follows the description of start(); that run() is not a method meant to be called directly and, for a thread created with a Runnable, calls the run of that task follows the description of run(); and that join() waits for that thread to finish and returns right away, without waiting, for a thread that has not started follows the descriptions of join() and join(long). That a thread is created as a Thread object and starts when start() of that object is called follows the beginning of chapter 17 of the Java Language Specification (Java SE 21), and that the program starts execution by calling the main method of a class follows section 12.1. However, section 12.1 does not specify the thread that runs main or its name, so the name main for that thread and the numbering order in which the first thread created without a name is Thread-0 and the second is Thread-1 are not defined by the specification but were observed by running on this JDK. The number of newly started threads is the value counted by the JVM and could differ if a thread were started separately inside the JVM, but that did not happen on the PC used to write this lab. The code on the screen uses only classes in java.lang, so it has no import line and has the same form as running with java Main. Every combination starts t and waits for it to finish with join before it starts t2, so the order of the output is fixed, and the order when there is no join or when two threads move at the same time is not covered by this lab and was not checked by execution. Beyond that, implementing Runnable or extending Thread, giving a thread a name, calling start() twice, the state changes of a thread, virtual threads, and thread pools are not covered. The state changes are covered in the in-depth lab "Creating threads and thread states".
Previous lab: Annotations · Next lab: Locks (synchronized)
Struck-through text was removed from the first version of the code; highlighted text was added.