陷阱 - 扩展 java.lang.Thread
Thread
类的 javadoc 显示了两种定义和使用线程的方法:
使用自定义线程类:
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeThread p = new PrimeThread(143);
p.start();
使用 Runnable
:
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
(来源: java.lang.Thread
javadoc 。)
自定义线程类方法有效,但它有一些问题:
-
在使用经典线程池,执行器或 ForkJoin 框架的上下文中使用
PrimeThread
是很尴尬的。 (这并非不可能,因为PrimeThread
间接实现了Runnable
,但使用自定义的Thread
类作为Runnable
肯定是笨拙的,并且可能不可行……取决于类的其他方面。) -
其他方法存在更多错误的机会。例如,如果你在未委托
Thread.start()
的情况下声明了PrimeThread.start()
,那么你最终会得到一个在当前线程上运行的线程。
将线程逻辑放入 Runnable
的方法避免了这些问题。实际上,如果你使用匿名类(Java 1.1 以上)来实现 Runnable
,结果将比上面的示例更简洁,更易读。
final long minPrime = ...
new Thread(new Runnable() {
public void run() {
// compute primes larger than minPrime
. . .
}
}.start();
使用 lambda 表达式(Java 8 以后),上面的示例将变得更加优雅:
final long minPrime = ...
new Thread(() -> {
// compute primes larger than minPrime
. . .
}).start();