Java Language Pitfall - Extending 'java.lang.Thread'

Example

The javadoc for the Thread class shows two ways to define and use a thread:

Using a custom thread class:

 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();

Using a 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();

(Source: java.lang.Thread javadoc.)

The custom thread class approach works, but it has a few problems:

  1. It is awkward to use PrimeThread in a context that uses a classic thread pool, an executor, or the ForkJoin framework. (It is not impossible, because PrimeThread indirectly implements Runnable, but using a custom Thread class as a Runnable is certainly clumsy, and may not be viable ... depending on other aspects of the class.)

  2. There is more opportunity for mistakes in other methods. For example, if you declared a PrimeThread.start() without delegating to Thread.start(), you would end up with a "thread" that ran on the current thread.

The approach of putting the thread logic into a Runnable avoids these problems. Indeed, if you use an anonymous class (Java 1.1 onwards) to implement the Runnable the result is more succinct, and more readable than the examples above.

 final long minPrime = ...
 new Thread(new Runnable() {
     public void run() {
         // compute primes larger than minPrime
          . . .
     }
 }.start();

With a lambda expression (Java 8 onwards), the above example would become even more elegant:

 final long minPrime = ...
 new Thread(() -> {
    // compute primes larger than minPrime
     . . .
 }).start();