CodeQL 文档

构造函数中的线程启动

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

单击以在 CodeQL 代码库中查看查询

在构造函数中启动线程可能会导致意外结果。如果扩展了该类,则线程可能在子类构造函数完成初始化之前启动,这可能不是预期的。

建议

避免在构造函数中启动线程。通常,类的构造函数只构造线程对象,应该提供一个单独的 start 方法来启动由构造函数创建的线程对象。

示例

在以下示例中,由于 Test 构造函数隐式调用 Super 构造函数,因此在 Super 构造函数中创建的线程可能在 this.name 初始化之前启动。因此,程序可能会输出“hello ”,然后输出一个空字符串。

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");
    }
}

在以下修改后的示例中,在 Super 构造函数中创建的线程不会在构造函数中启动;mainthis.name 初始化之后启动线程。这会导致程序输出“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();
    }
}

参考文献

  • ©GitHub, Inc.
  • 条款
  • 隐私