天天看點

Thread源碼分析

1、Runnable接口源碼:

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

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

1 public class Thread implements Runnable{
2 
3 }      

  Runnable接口僅有一個run()方法,Thread類實作了Runnable接口,是以,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方法:

Thread源碼分析
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     }      
Thread源碼分析

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

  4、Thread的start方法的實作:

Thread源碼分析
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 }      
Thread源碼分析

  這裡主要的是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接口實作的線程類需要這樣啟動的原因。