Programming basics - Techniques and Tricks IV -

Joe

Thành viên VIP
21/1/13
2,701
1,246
113
Hi

7) Thread or Runnable or Callable? It isn't the question of peach or pear. It's about the way how one can take the best out of them. If you loiter on the Web you would learn tons of blogs about Thread and Runnable or Callable. Therefore I have no need to dig into details, but give you some most relevant facts about Thread and Runnable or Callable.

  • Thread is an independent entity that runs independently from its parents (main thread or app), has its own environment, but it could share some resources owned by the main "thread" (i.e. main program) . You build your own thread on the API Thread as an extension of it. And other objects can be extended ONLY from this thread (Single Inheritance).
  • Runnable or Callable is an implementation of the Interface Runnable or Callable. It is "known" that Runnable/Callable requires "less" resources than a Thread/Task, but that is only the half-truth. It's because a Runnable or Callable needs a Thread to kick it up. The fact that a Thread has to patronize a Runnable or a Callable makes the statement of "less resources requirement" looking sarcastic ! The full truth lies in the Single-Inheritance paradigm of JAVA. With Runnable or Callable you open a gateway to other objects without breaking the Single-Inheritance paradigm. A Runnable / Callable Object behaves like a Thread or Task (1st. inheritance) and could be an extension of any other object (2nd. inheritance). And if a Runnable or Callable is an implementation of several other interfaces it becomes the heir of different objects (multiple inheritance).

Knowing that you could work with Thread and Runnable better and more precise.
  • For a long-life processing Thread is the first choice.
  • For a short-life work or a small task that runs in a ThreadPool Runnable or Callable object is the best.
A long-life process is, for example, a session that starts and lasts along with the main program. A Network-Monitoring Thread is a long-life Thread while a downloading process that takes even an hour is a short-life Thread/Task (a Runnable or Callable). ThreadPool is usually the playground for Runnable and Callable while Thread has its own playground.
PHP:
import java.util.concurrent.*;
// Test6 is a Thread whose playground is the same of the main thread (or app)
public class Test6 extends Thread {
  public Test6() {
    this.start(); // self-starter
  }
  public void run() {
    // establish a playground for Runnable and Callable
    ExecutorService pool = Executors.newWorkStealingPool();
    // Runnable as Lambda Expression
    pool.execute(() -> {
      System.out.println("ThreadPool with execute of a Runnable");
    });
    // Callable as a small task
    Future<String> f = pool.submit(() -> {
     System.out.println("ThreadPool with submit of a Callable");
      return "done";
    });
    try {
      System.out.println("Return of submit:"+f.get());
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    pool.shutdown();
    System.out.println("Thread is down");
  }
  //
  public static void main(String... A) throws Exception {
    new Test6();
    System.out.println("MainThread is down");
  }
}
Code:
C:\Test>javac -g:none -d ./classes Test6.java

C:\Test>java Test6
MainThread is down
ThreadPool with execute of a Runnable
ThreadPool with submit of a Callable
Return of submit:done
Thread is down

C:\Test>
As you see, the main thread exited but the run-along Thread is still busy with its own processing: Setup a ThreadPool, executing a Runnable, then submitting a Callable and finally waits for their end. Hence the message "Thread is down" is the last. But if you put the waiting activity of "submit" out of service as following

PHP:
import java.util.concurrent.*;
public class Test6 extends Thread {
  public Test6() {
    this.start(); // self-starter
  }
  public void run() {
    ExecutorService pool = Executors.newWorkStealingPool();
    // Runnable as Lambda Expression
    pool.execute(() -> {
      System.out.println("ThreadPool with execute of a Runnable");
    });
    // Callable as a small task
    Future<String> f = pool.submit(() -> {
      System.out.println("ThreadPool with submit of a Callable");
      return "done";
    });
    /*----------------------------------------------------------
    try {
      System.out.println("Return of submit:"+f.get());
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    pool.shutdown();
    ------------------------------------------------------------*/
    System.out.println("Thread is down");
  }
  //
  public static void main(String... A) throws Exception {
    new Test6();
    System.out.println("MainThread is down");
  }
}
Code:
C:\Test>javac -g:none -d ./classes Test6.java

C:\Test>java Test6
MainThread is down
ThreadPool with execute of a Runnable
Thread is down
ThreadPool with submit of a Callable
C:\links\java\Test>

C:\Test>
The parallel Thread won't have to wait for the submit-result and can end after completing the "submit" ("Thread is down" before "ThreadPool with submit of a Callable"). The reason is that submit as a "plea" does NOT trigger an immediate execution of the task (see my previous section).
BUT: if you switch the position of "execute" with "submit" the execute operation starts before the parallel Thread comes to the last line System.out.println("....").
PHP:
import java.util.concurrent.*;
public class Test6 extends Thread {
  public Test6() {
    this.start(); // self-starter
  }
  public void run() {
    ExecutorService pool = Executors.newWorkStealingPool();
    // Callable as a small task
    Future<String> f = pool.submit(() -> {
      System.out.println("ThreadPool with submit of a Callable");
      return "done";
    });
    // Runnable as Lambda Expression BEHIND pool.submi
    pool.execute(() -> {
      System.out.println("ThreadPool with execute of a Runnable");
    });
    /*----------------------------------------------------------
    try {
      System.out.println("Return of submit:"+f.get());
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    pool.shutdown();
    ------------------------------------------------------------*/
    System.out.println("Thread is down");
  }
  //
  public static void main(String... A) throws Exception {
    new Test6();
    System.out.println("MainThread is down");
  }
}
Code:
C:\Test>javac -g:none -d ./classes Test6.java

C:\Test>java Test6
MainThread is down
ThreadPool with submit of a Callable
ThreadPool with execute of a Runnable
Thread is down
C:\Test>
The following snippet shows you how a Thread has to patronize a Runnable or a Callable;
PHP:
import java.util.concurrent.*;
public class Test6a extends Thread {
  public Test6a() {
    this.start(); // self-starter
  }
  private class aRunnable implements Runnable {
    public aRunnable() { }
    public void run() {
      System.out.println("Inside aRunnable");
    }
  }
  private class aCallable implements Callable<String> {
    public aCallable() { }
    public String call() {
      System.out.println("Inside aCallable");
      return "done";
    }
  } 
  public void run() {
    new Thread(new aRunnable()).start();
    FutureTask<String> fTask = new FutureTask<>(new aCallable());
    new Thread(fTask).start();
    try {
      System.out.println("--->"+fTask.get());
    } catch (Exception ex) { }
    System.out.println("Thread is down");
  }
  //
  public static void main(String... A) throws Exception {
    new Test6a();
    System.out.println("MainThread is down");
  }
}
Code:
C:\Test>javac -g:none -d ./classes Test6a.java

C:\Test>java Test6a
MainThread is down
Inside aRunnable
Inside aCallable
--->done
Thread is down

C:\Test>
(Cont.)
 
Sửa lần cuối: