天天看點

2-5-Java多線程-建立線程的Runnable接口方法及Thread源碼解析建立線程的Runnable接口方法

建立線程的Runnable接口方法

public interface Runnable

Runnable 接口應該由那些打算通過某一線程執行其執行個體的類來實作。類必須定義一個稱為 run 的無參數方法。

設計該接口的目的是為希望在活動時執行代碼的對象提供一個公共協定。例如,Thread 類實作了 Runnable。激活的意思是說某個線程已啟動并且尚未停止。

此外,Runnable 為非 Thread 子類的類提供了一種激活方式。通過執行個體化某個 Thread 執行個體并将自身作為運作目标,就可以運作實作 Runnable 的類而無需建立 Thread 的子類

大多數情況下,如果隻想重寫 run() 方法,而不重寫其他 Thread 方法,那麼應使用Runnable接口。這很重要,因為除非程式員打算修改或增強類的基本行為,否則不應為該類建立子類。

使用方法

  • 定義類實作runnable接口(避免單繼承的局限性)
  • 覆寫接口中run方法,将線程任務代碼定義到run方法中
  • 建立thread類的對象(隻有通過線程對線才能操作線程方法)
  • 将runnable接口的子類對象作為參數傳遞給Thread類的構造函數
  • 調用Thread類的Start方法開啟線程

代碼示例-1

/**
 * Created by Egg on 2016/10/21.
 *建立線程的第二種方式
 * 1. 定義類實作runnable接口(避免單繼承的局限性)
 * 2. 覆寫接口中run方法,将線程任務代碼定義到run方法中
 * 3. 建立thread類的對象(隻有通過線程對線才能操作線程方法)
 * 4. 将runnable接口的子類對象作為參數傳遞給Thread類的構造函數
 * 5. 調用Thread類的Start方法開啟線程
 *
 * 第二種方式實作runnable接口避免了單繼承的局限性,是以較為常用
 *
 *       public Thread(Runnable target) {
         init(null, target, "Thread-" + nextThreadNum(), 0);
         }
         @Override
         public void run() {
             if (target != null) {
             target.run();
             }
         }
 */
class Demo implements Runnable
{
    private String name;
    Demo(String name)
    {
        this.name = name;
    }
    public void run()
    {
        for (int i =  ; i <  ; i ++)
        {
            System.out.println(name + i);
        }
    }

}
public class ThreadDemo
{
    public static void main(String[] args) {
        /*
        * 建立Runnable子類的對象
        * 而非線程對象
        * 此處runnable對象是Thread類的一個參數
        * */
        Demo d1 = new Demo("AAA");
        Demo d2 = new Demo("BBB");
        Demo d3 = new Demo("CCC");
        Demo d4 = new Demo("DDD");
        Thread t1 = new Thread(d1);
        Thread t2 = new Thread(d2);
        Thread t3 = new Thread(d3);
        Thread t4 = new Thread(d4);
        t2.start();
        d1.run();

        t3.start();
        t4.run();
    }
}
           

使用Runnable接口的好處

假設Student類繼承了Person,但現在有一個需求,Student中有一段CODE需要多線程執行,然而Java隻支援單繼承.

可以讓Person也繼承Thread,然而這會讓所有的Person的子類也繼承Thread是以并不是一種好的辦法.

是以我們讓Student類實作Runnable接口

2-5-Java多線程-建立線程的Runnable接口方法及Thread源碼解析建立線程的Runnable接口方法

Runnable接口避免了單繼承的局限性,是以較為常用.

實作runnable接口的方式更加面向對象,線程分為兩部分,一部分是線程對象,一部分是線程任務.繼承Thread類會讓線程對象和線程任務耦合在一起.一旦建立Thread類的子對象,既是線程對象又有線程任務,實作runnable接口将線程任務單獨分離出來封裝為對象,對線程任務和線程對象解耦.

源碼解析

  • 定義類實作runnable接口(避免單繼承的局限性)
  • 覆寫接口中run方法,将線程任務代碼定義到run方法中
  • 建立thread類的對象(隻有通過線程對線才能操作線程方法)
  • 将runnable接口的子類對象作為參數傳遞給Thread類的構造函數(提供run方法)
  • 調用Thread類的Start方法開啟線程
/**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
           
可以看到JDK源碼中,Thread對象在調用run方法時會判斷target如果target不等于null那麼就會調用target的run方法,那麼target是什麼呢?
/* What will be run. */
    private Runnable target;

     /**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, target, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     *
     * @param  target
     *         the object whose {@code run} method is invoked when this thread
     *         is started. If {@code null}, this classes {@code run} method does
     *         nothing.
     */
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), );
    }

    /**
     * Initializes a Thread with the current AccessControlContext.
     * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext)
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null);
    }
           
原來target是Thread類的一個Runnable類型的成員變量,其在構造函數中被初始化

繼續閱讀