陷阱 - 擴充套件 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 。)

自定義執行緒類方法有效,但它有一些問題:

  1. 在使用經典執行緒池,執行器或 ForkJoin 框架的上下文中使用 PrimeThread 是很尷尬的。 (這並非不可能,因為 PrimeThread 間接實現了 Runnable,但使用自定義的 Thread 類作為 Runnable 肯定是笨拙的,並且可能不可行……取決於類的其他方面。)

  2. 其他方法存在更多錯誤的機會。例如,如果你在未委託 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();