原文:https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88487735
THI00-J. Do not invoke Thread.run()
使用该方法启动线程具有迷惑性,看起来是启动新的线程执行方法,但实际上,执行方法的线程是不对的。
调用Thread.start()
才能启动新的线程执行线程的run()
方法,直接调用Thread
对象的run()
方法并不能达到目的。事实上,调用Thread
对象的run()
方法是当前线程执行了run()
方法中的语句,而非新启动的线程。更糟糕的是,如果这个Thread
对象是通过Thread
类的子类实例化的,并且这个子类并没有覆盖父类的run()
方法,那么调用它的run()
方法什么都不会执行。总而言之,代码中一定不要直接调用Thread
对象的run()
方法。
不规范的代码
下面的代码从当前线程执行了run()
方法:
public final class Foo implements Runnable {
@Override public void run() {
// ...
}
public static void main(String[] args) {
Foo foo = new Foo();
new Thread(foo).run();
}
}
这里new
出来的线程根本不会启动,我们想当然的认为调用run()
方法就启动的新线程,但结果是,当前线程执行了run()
方法中的语句。
规范的代码
下面的代码通知Java运行时启动一个新的线程执行run()
方法:
public final class Foo implements Runnable {
@Override public void run() {
// ...
}
public static void main(String[] args) {
Foo foo = new Foo();
new Thread(foo).start();
}
}
例外
THI00-J-EX0
在进行单元测试时,我们可能会直接调用Thread
对象的run()
方法,测试run()
方法中的逻辑,但是需要注意,不要以这种方式在多线程环境下测试。
public void sampleRunTest() {
Thread thread = new Thread(new Runnable() {
@Override public void run() {
// ...
}
});
((Runnable) thread).run(); // THI00-J-EX0: Does not start a new thread
}
在调用run()
方法前,将线程对象强制转换成Runnable对象,明确告知是有意的调用run()
方法进行测试,同时强烈建议给这行代码加一个明确的注释。
THI00-J-EX1
用于创建新线程的运行时系统代码是允许直接调用Thread
对象的run()
方法的,对于Java运行时系统,这样直接调用显然是必要的,然而需要注意,上层用户代码需要采用这种调用方式的场景是几乎没有的。