天天看點

Thread、Runnable和Callable

1. 關于Thread的Runnable和Callable接口

其實非常簡單:其實他們的差別就是Callable有傳回值并且可以抛出異常。

public interface Runnable {

public void run();

}

public interface Callable<V> {

V call() throws Exception;

}

2. Thread類

 1、Runnable接口源碼:

1 public interface Runnable {
2     public void run();
3 }      

  2、Thread類與Runnable接口的繼承關系

1 public class Thread implements Runnable{
2 
3 }      

  Runnable接口僅有一個run()方法,Thread類實作了Runnable接口。

  3、構造函數

1 public Thread() {
2     init(null, null, "Thread-" + nextThreadNum(), 0);
3 }      
1 public Thread(Runnable target) {
2     init(null, target, "Thread-" + nextThreadNum(), 0);
3 }      
1 public Thread(ThreadGroup group, Runnable target) {
2     init(group, target, "Thread-" + nextThreadNum(), 0);
3 }      
1 public Thread(String name) {
2     init(null, null, name, 0);
3 }
                  還有其它的構造方法,此處省略。。。      

  這裡的第三個參數是設定線程的名稱,從下面的代碼中可以看出,生成名稱的規則是:”Thread-”加上建立的線程的個數(第幾個)。

繼續檢視init方法:

1 /**
 2      * Initializes a Thread.
 3      *
 4      * @param g the Thread group
 5      * @param target the object whose run() method gets called
 6      * @param name the name of the new Thread
 7      * @param stackSize the desired stack size for the new thread, or
 8      *        zero to indicate that this parameter is to be ignored.
 9      */
    //ThreadGroup:線程組表示一個線程的集合。此外,線程組也可以包含其他線程組。線程組構成一棵樹,在樹中,除了初始線程組外,每個線程組都有一個父線程組。
10     private void init(ThreadGroup g, Runnable target, String name,
11                       long stackSize) {
12     Thread parent = currentThread();
13     SecurityManager security = System.getSecurityManager();
14     if (g == null) {
15         /* Determine if it's an applet or not */
16         
17         /* If there is a security manager, ask the security manager
18            what to do. */
19         if (security != null) {
20         g = security.getThreadGroup();
21         }
22 
23         /* If the security doesn't have a strong opinion of the matter
24            use the parent thread group. */
25         if (g == null) {
26         g = parent.getThreadGroup();
27         }
28     }
29 
30     /* checkAccess regardless of whether or not threadgroup is
31            explicitly passed in. */
32     g.checkAccess();
33 
34     /*
35      * Do we have the required permissions?
36      */
37     if (security != null) {
38         if (isCCLOverridden(getClass())) {
39             security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
40         }
41     }
42 
43 
44         g.addUnstarted();
45 
46     this.group = g;
      

    //每個線程都有一個優先級,高優先級線程的執行優先于低優先級線程。每個線程都可以或不可以标記為一個守護程式。當某個線程中運作的代碼建立一個新

Thread

對象時,該新線程的初始優先級被設定為建立線程的優先級,并且當且僅當建立線程是守護線程時,新線程才是守護程式。

47     this.daemon = parent.isDaemon();
48     this.priority = parent.getPriority();
49     this.name = name.toCharArray();
50     if (security == null || isCCLOverridden(parent.getClass()))
51         this.contextClassLoader = parent.getContextClassLoader();
52     else
53         this.contextClassLoader = parent.contextClassLoader;
54     this.inheritedAccessControlContext = AccessController.getContext();
55     this.target = target;
56     setPriority(priority);
57         if (parent.inheritableThreadLocals != null)
58         this.inheritableThreadLocals =
59         ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
60         /* Stash the specified stack size in case the VM cares */
61         this.stackSize = stackSize;
62 
63         /* Set thread ID */
64         tid = nextThreadID();
65     }      

  初始化時設定了是否為守護線程,優先級,初始化名稱。

  4、Thread的start方法的實作:

1 public synchronized void start() {
 2         /**
 3      * This method is not invoked for the main method thread or "system"
 4      * group threads created/set up by the VM. Any new functionality added 
 5      * to this method in the future may have to also be added to the VM.
 6      *
 7      * A zero status value corresponds to state "NEW".
 8          */
 9         if (threadStatus != 0)
10             throw new IllegalThreadStateException();
11         group.add(this);
12         start0();
13         if (stopBeforeStart) {
14         stop0(throwableFromStop);
15     }
16 }      

  這裡主要的是start0方法;檢視其實作:

1 private native void start0();
      

  這裡使用了本地調用,通過C代碼初始化線程需要的系統資源。可見,線程底層的實作是通過C代碼去完成的。

4、Thread的run方法的實作

1 public void run() {
2     if (target != null) {
3         target.run();
4     }
5 }      

  這裡的target實際上要儲存的是一個Runnable接口的實作的引用:

1 private Runnable target;      

  是以使用繼承Thread建立線程類時,需要重寫run方法,因為預設的run方法什麼也不幹。

  而當我們使用Runnable接口實作線程類時,為了啟動線程,需要先把該線程類執行個體初始化一個Thread,實際上就執行了如下構造函數:

1 public Thread(Runnable target) {
2     init(null, target, "Thread-" + nextThreadNum(), 0);
3 }      

  即是把線程類的引用儲存到target中。這樣,當調用Thread的run方法時,target就不為空了,而是繼續調用了target的run方法,是以我們需要實作Runnable的run方法。這樣通過Thread的run方法就調用到了Runnable實作類中的run方法。

  這也是Runnable接口實作的線程類需要這樣啟動的原因。

另外java中的Executor 類也是非常簡單的接口,隻有一個execute()方法

public interface Executor {

void execute(Runnable command);

}

Excutor執行已送出的

Runnable

任務的對象。此接口提供一種将任務送出與每個任務将如何運作的機制(包括線程使用的細節、排程等)分離開來的方法。通常使用Executor而不是顯式地建立線程。例如,可能會使用以下方法,而不是為一組任務中的每個任務調用new Thread(new(RunnableTask())).start():

Executor executor = anExecutor;
 executor.execute(new RunnableTask1());
 executor.execute(new RunnableTask2());
 ...
       

不過, Executor 接口并沒有嚴格地要求執行是異步的。在最簡單的情況下,執行程式可以在調用方的線程中立即運作已送出的任務:

class DirectExecutor implements Executor {
     public void execute(Runnable r) {
         r.run();
     }
 }      

更常見的是,任務是在某個不是調用方線程的線程中執行的。以下執行程式将為每個任務生成一個新線程。

class ThreadPerTaskExecutor implements Executor {
     public void execute(Runnable r) {
         new Thread(r).start();
     }
 }      

許多 Executor 實作都對排程任務的方式和時間強加了某種限制。以下執行程式使任務送出與第二個執行程式保持連續,這說明了一個複合執行程式。

class SerialExecutor implements Executor {
     final Queue<Runnable> tasks = new LinkedBlockingQueue<Runnable>();
     final Executor executor;
     Runnable active;

     SerialExecutor(Executor executor) {
         this.executor = executor;
     }

     public synchronized void execute(final Runnable r) {
         tasks.offer(new Runnable() {
             public void run() {
                 try {
                     r.run();
                 } finally {
                     scheduleNext();
                 }
             }
         });
         if (active == null) {
             scheduleNext();
         }
     }

     protected synchronized void scheduleNext() {
         if ((active = tasks.poll()) != null) {
             executor.execute(active);
         }
     }
 }