Three Ways to Create Threads in Java: Extending Thread, Implementing Runnable, and Using Callable/Future
This article explains the three primary techniques for creating threads in Java—subclassing Thread, implementing the Runnable interface, and using Callable with Future—provides complete code examples for each method, and compares their advantages and disadvantages for practical multithreading development.
1. Creating Threads in Java
1.1 Extending the Thread class
Define a subclass of Thread and override its run() method, which contains the thread's execution logic.
Instantiate the subclass to create a thread object.
Call start() on the thread object to begin execution.
Example code:
package com.thread;
public class FirstThreadTest extends Thread {
int i = 0;
// Override run method – the execution body of the thread
public void run() {
for (; i < 100; i++) {
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
if (i == 20) {
new FirstThreadTest().start();
new FirstThreadTest().start();
}
}
}
}In the code above, Thread.currentThread() returns the currently executing thread, and getName() returns its name.
1.2 Implementing the Runnable interface
Create a class that implements Runnable and override its run() method.
Instantiate the Runnable implementation and pass it as the target to a new Thread object.
Start the thread by calling start() on the Thread object.
Example code:
package com.thread;
public class RunnableThreadTest implements Runnable {
private int i;
public void run() {
for (i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 20) {
RunnableThreadTest rtt = new RunnableThreadTest();
new Thread(rtt, "New Thread 1").start();
new Thread(rtt, "New Thread 2").start();
}
}
}
}When start() is invoked, the overridden run() method executes; after it finishes, the thread terminates.
1.3 Using Callable and Future
(1) Define a class that implements Callable<V> and implement the call() method, which can return a value and throw checked exceptions.
(2) Wrap the Callable instance with a FutureTask , which implements both Future and Runnable .
(3) Use the FutureTask as the target of a new Thread and start it.
(4) Retrieve the result with FutureTask.get() after the thread completes.
Example code:
package com.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableThreadTest implements Callable
{
public static void main(String[] args) {
CallableThreadTest ctt = new CallableThreadTest();
FutureTask
ft = new FutureTask<>(ctt);
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " 的循环变量i的值" + i);
if (i == 20) {
new Thread(ft, "Thread with return value").start();
}
}
try {
System.out.println("子线程的返回值:" + ft.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception {
int i = 0;
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
return i;
}
}2. Comparison of the Three Thread Creation Methods
2.1 Runnable/Callable vs. Extending Thread
Advantages of Runnable/Callable: The thread class can extend another class, and multiple threads can share the same target object, which is useful for processing the same resource concurrently and follows object‑oriented principles.
Disadvantages: Accessing the current thread requires Thread.currentThread() , making the code slightly more complex.
2.2 Extending Thread
Advantages: Simpler to write; the current thread can be accessed directly via this without calling Thread.currentThread() .
Disadvantages: Since the class already extends Thread , it cannot extend any other class.
2.3 Runnable vs. Callable
(1) Runnable defines run() , while Callable defines call() .
(2) Callable can return a result; Runnable cannot.
(3) call() can throw checked exceptions; run() cannot.
(4) Callable tasks produce a Future object, allowing you to check completion, retrieve results, or cancel the task.
Source: cnblogs.com/songshu120/p/7966314.html
For additional interview questions and resources, see the linked WeChat articles at the end of the original post.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.