Avoid Starting Threads in Constructors
What is it?
This rule is triggered when a Thread.start()
method is called within a constructor of a non-final
class.
Why apply it?
Starting a thread in a constructor can lead to complex and hard-to-debug issues, especially if the class is extended. The child class might not be fully initialized when the thread starts.
How to fix it?
Avoid starting a thread within the constructor. Instead, provide a method to start the thread after the construction of the object is complete.
Examples
Example 1:
Negative
The negative example starts a thread in the constructor, risking it is started before the object is fully initialized.
public class MyClass {
private Thread thread = null;
public MyClass(Runnable runnable) {
thread = new Thread(runnable);
thread.start(); // Noncompliant
}
}
public class Main {
public static void main(String[] args) {
MyClass myClass = new MyClass(() -> System.out.println("Running in thread"));
// Risky: the thread has already started before myClass is fully available
}
}
Example 2:
Positive
In the positive example, the thread is started via a separate method, ensuring the object is fully initialized before starting the thread.
public class MyClass {
private Thread thread = null;
public MyClass(Runnable runnable) {
thread = new Thread(runnable);
}
public void startThread() {
thread.start(); // Compliant
}
}
public class Main {
public static void main(String[] args) {
MyClass myClass = new MyClass(() -> System.out.println("Running in thread"));
myClass.startThread();
}
}
Negative
In this negative example, the thread starts in the constructor leading to potential concurrency issues with inheritance.
public class Worker {
private Thread workerThread = null;
public Worker(Runnable task) {
workerThread = new Thread(task);
workerThread.start(); // Noncompliant
}
}
public class Manager {
public static void main(String[] args) {
Worker worker = new Worker(() -> {
System.out.println("Worker is executing a task");
});
// The thread may operate on an incompletely initialized object
}
}
Example 3:
Positive
In the positive example, a separate initialization method is used to start the thread after the object is fully constructed.
public class Worker {
private Thread workerThread = null;
public Worker(Runnable task) {
workerThread = new Thread(task);
}
public void startWorker() {
workerThread.start(); // Compliant
}
}
public class Manager {
public static void main(String[] args) {
Worker worker = new Worker(() -> {
System.out.println("Worker is executing a task");
});
worker.startWorker(); // Safe to start after construction
}
}