CodeQL documentation

Start of thread in constructor

ID: java/thread-start-in-constructor
Kind: problem
Severity: warning
Precision: medium
Tags:
   - reliability
   - correctness
   - concurrency
Query suites:
   - java-security-and-quality.qls

Click to see the query in the CodeQL repository

Starting a thread within a constructor may cause unexpected results. If the class is extended, the thread may start before the subclass constructor has completed its initialization, which may not be intended.

Recommendation

Avoid starting threads in constructors. Typically, the constructor of a class only constructs the thread object, and a separate start method should be provided to start the thread object created by the constructor.

Example

In the following example, because the Test constructor implicitly calls the Super constructor, the thread created in the Super constructor may start before this.name has been initialized. Therefore, the program may output “hello “ followed by a null string.

class Super {
    public Super() {
        new Thread() {
            public void run() {
                System.out.println(Super.this.toString());
            }
        }.start(); // BAD: The thread is started in the constructor of 'Super'.
    }

    public String toString() {
        return "hello";
    }
}

class Test extends Super {
    private String name;
    public Test(String nm) {
        // The thread is started before
        // this line is run
        this.name = nm;
    }

    public String toString() {
        return super.toString() + " " + name;
    }

    public static void main(String[] args) {
        new Test("my friend");
    }
}

In the following modified example, the thread created in the Super constructor is not started within the constructor; main starts the thread after this.name has been initialized. This results in the program outputting “hello my friend”.

class Super {
    Thread thread;
    public Super() {
        thread = new Thread() {
            public void run() {
                System.out.println(Super.this.toString());
            }
        };
    }

    public void start() {  // good
        thread.start();
    }
    
    public String toString() {
        return "hello";
    }
}

class Test extends Super {
    private String name;
    public Test(String nm) {
        this.name = nm;
    }

    public String toString() {
        return super.toString() + " " + name;
    }

    public static void main(String[] args) {
        Test t = new Test("my friend");
        t.start();
    }
}

References