Java Threads and Runnable
A thread is a separate path of execution inside one program. A Runnable holds the work, and a Thread runs that work on its own path.
Two workers count into their own slots
Each worker counts its own list and stores the count in its own task object. The main thread joins both workers and then prints the counts in a fixed order.
import java.util.List;
public class Main {
public static void main(String[] args) throws Exception {
CountTask first = new CountTask(List.of(4, 8, 15));
CountTask second = new CountTask(List.of(16, 23, 42, 7));
Thread firstThread = new Thread(first);
Thread secondThread = new Thread(second);
firstThread.start();
secondThread.start();
firstThread.join();
secondThread.join();
System.out.println("Worker 1 count: " + first.result);
System.out.println("Worker 2 count: " + second.result);
}
}
class CountTask implements Runnable {
private final List<Integer> values;
int result;
CountTask(List<Integer> values) {
this.values = values;
}
public void run() {
int count = 0;
for (int value : values) {
count++;
}
result = count;
}
}Calling run stays on the main thread
The task records the name of the thread that runs it into its own slot. The main thread calls run directly, so the slot holds the main thread name.
public class Main {
public static void main(String[] args) {
NameTask task = new NameTask();
Thread thread = new Thread(task, "worker");
thread.run();
System.out.println("Name seen by run: " + task.name);
}
}
class NameTask implements Runnable {
String name;
public void run() {
name = Thread.currentThread().getName();
}
}Calling start runs on the worker thread
The same task runs again with the same thread name available. The main thread calls start this time, joins, and prints the name the worker recorded.
public class Main {
public static void main(String[] args) throws Exception {
NameTask task = new NameTask();
Thread thread = new Thread(task, "worker");
thread.start();
thread.join();
System.out.println("Name seen by start: " + task.name);
}
}
class NameTask implements Runnable {
String name;
public void run() {
name = Thread.currentThread().getName();
}
}Example
public class Main {
public static void main(String[] args) throws Exception {
LengthTask first = new LengthTask("concurrent");
LengthTask second = new LengthTask("java");
LengthTask third = new LengthTask("thread");
Thread firstThread = new Thread(first);
Thread secondThread = new Thread(second);
Thread thirdThread = new Thread(third);
firstThread.start();
secondThread.start();
thirdThread.start();
firstThread.join();
secondThread.join();
thirdThread.join();
System.out.println(first.word + ": " + first.length);
System.out.println(second.word + ": " + second.length);
System.out.println(third.word + ": " + third.length);
}
}
class LengthTask implements Runnable {
final String word;
int length;
LengthTask(String word) {
this.word = word;
}
public void run() {
length = word.length();
}
}Key points
- A Runnable describes the work, and a Thread carries that work to its own path.
- The start method asks for a new thread, and the run method holds the work itself.
- Calling run directly is an ordinary method call on the current thread.
- The join method pauses the calling thread until the worker finishes.
- Workers store results in their own slots, and the main thread prints after joining.
In this example, three workers each measure one word and store the length in their own task. The main thread joins all three workers and prints the lengths in task order.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Why does the main thread join the workers before printing their results?