Java 並發 --- Thread 源碼淺析__Java

來源:互聯網
上載者:User

在多線程編程中,如果要使用線程來執行任務,那麼最簡單的方式就是使用Thread類來建立一個線程,當然也可以使用線程池的方式。
線程是在進程中執行的單位,線程的資源開銷相對於進程的開銷是相對較少的,所以我們一般建立線程執行,而不是進程執行。
本文不是學習Thread的使用,而是通過Thread類來一探線程從建立到結束的過程。 繼承體系


Thread類實現了Runnable介面,因此Thread不僅是一個線程類,也是一個特殊的執行任務類。 資料結構

  //線程名稱的位元組數組  private volatile char  name[];  //線程優先順序  private int            priority;  private Thread         threadQ;  private long           eetop;  //線程是否單步  private boolean     single_step;  //是否是守護線程  private boolean     daemon = false;  /* JVM state */  private boolean     stillborn = false;  // 要執行的run方法的對象  private Runnable target;  // 這個線程的線程組  private ThreadGroup group;  /* The context ClassLoader for this thread */  // 這個線程的上下文類載入器  private ClassLoader contextClassLoader;  /* The inherited AccessControlContext of this thread */  private AccessControlContext inheritedAccessControlContext;  //線程編號  private static int threadInitNumber;  /* ThreadLocal values pertaining to this thread. This map is maintained   * by the ThreadLocal class.    */  // ThreadLocal相關   ThreadLocal.ThreadLocalMap threadLocals = null;  /*   * InheritableThreadLocal values pertaining to this thread. This map is   * maintained by the InheritableThreadLocal class.   */  ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;  /*   * The requested stack size for this thread, or 0 if the creator did   * not specify a stack size.  It is up to the VM to do whatever it   * likes with this number; some VMs will ignore it.   */   // 給這個線程設定的棧的大小,預設為0   private long stackSize;  /*   * JVM-private state that persists after native thread termination.   */  private long nativeParkEventPointer;   //線程id  private long tid;  /* For generating thread ID */  private static long threadSeqNumber;  /* Java thread status for tools,   * initialized to indicate thread 'not yet started'   */  //初始狀態   private volatile int threadStatus = 0;  /**   * The argument supplied to the current call to   * java.util.concurrent.locks.LockSupport.park.   * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker   * Accessed using java.util.concurrent.locks.LockSupport.getBlocker   */  volatile Object parkBlocker;  /* The object in which this thread is blocked in an interruptible I/O   * operation, if any.  The blocker's interrupt method should be invoked   * after setting this thread's interrupt status.   */  private volatile Interruptible blocker;  // 用於blocker 的鎖對象  private final Object blockerLock = new Object();  /**   * The minimum priority that a thread can have.   */   //最低優先順序  public final static int MIN_PRIORITY = 1; /**   * The default priority that is assigned to a thread.   */   // 線程預設的執行優先順序為 5  public final static int NORM_PRIORITY = 5;  /**   * The maximum priority that a thread can have.   */   // 線程執行的最高的優先順序為 10  public final static int MAX_PRIORITY = 10;

上面的屬性包含了線程的基本屬性,Thread 並不是一個執行任務,而是作為一個線程單位存在,其內部擁有可執行任務 target(Runnable 類型),這個我們在後面的方法中將會更加細緻的探討。
線程的優先順序在不同的平台上,對應的系統優先順序會不同,可能多個優先順序對應同一個系統優先順序,優先順序高的線程並不一定優先執行,這個由JVM來解釋並向系統提供參考。 線程狀態(生命週期)

public enum State {    /**     * Thread state for a thread which has not yet started.     */    NEW,    /**     * Thread state for a runnable thread.  A thread in the runnable     * state is executing in the Java virtual machine but it may     * be waiting for other resources from the operating system     * such as processor.     */    RUNNABLE,    /**     * Thread state for a thread blocked waiting for a monitor lock.     * A thread in the blocked state is waiting for a monitor lock     * to enter a synchronized block/method or     * reenter a synchronized block/method after calling     */    BLOCKED,    /**     * Thread state for a waiting thread.     */    WAITING,    /**     * Thread state for a waiting thread with a specified waiting time.     */    TIMED_WAITING,    /**     * Thread state for a terminated thread.     * The thread has completed execution.     */    TERMINATED;}

線程的狀態有NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED,官方文檔說得也很詳細。 構造方法

1、無參構造

public Thread() {    init(null, null, "Thread-" + nextThreadNum(), 0);}

2、指定執行任務

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

3、指定線程組和執行任務

public Thread(ThreadGroup group, Runnable target) {    init(group, target, "Thread-" + nextThreadNum(), 0);}

還有其它很多的構造方法,這裡就不一一羅列出來了,在構造方法中,都調用了init 方法來進行初始化。 init 方法

private void init(ThreadGroup g, Runnable target, String name,                  long stackSize, AccessControlContext acc) {    if (name == null) {        throw new NullPointerException("name cannot be null");    }    // 設定線程名稱    this.name = name.toCharArray();    //當前調用線程為 父線程    Thread parent = currentThread();    SecurityManager security = System.getSecurityManager();    if (g == null) {        /* Determine if it's an applet or not */        /* If there is a security manager, ask the security manager           what to do. */        if (security != null) {            g = security.getThreadGroup();        }        /* If the security doesn't have a strong opinion of the matter           use the parent thread group. */        if (g == null) {            g = parent.getThreadGroup();        }    }    /* checkAccess regardless of whether or not threadgroup is       explicitly passed in. */    g.checkAccess();    /*     * Do we have the required permissions?     */    if (security != null) {        if (isCCLOverridden(getClass())) {            security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);        }    }    g.addUnstarted();    this.group = g;    // 繼承父線程的相關屬性    this.daemon = parent.isDaemon();    this.priority = parent.getPriority();    if (security == null || isCCLOverridden(parent.getClass()))        this.contextClassLoader = parent.getContextClassLoader();    else        this.contextClassLoader = parent.contextClassLoader;    this.inheritedAccessControlContext =            acc != null ? acc : AccessController.getContext();    // 設定執行任務            this.target = target;    setPriority(priority);    if (parent.inheritableThreadLocals != null)        this.inheritableThreadLocals =            ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);    /* Stash the specified stack size in case the VM cares */    this.stackSize = stackSize;    /* Set thread ID */    // 設定線程id,nextThreadID()進行了同步處理    tid = nextThreadID();}

構造方法是被調用者線程執行的,因此調用者線程將作為父線程,新建立的線程繼承父線程的部分屬性。 run 方法

Thread繼承Runnable 介面,那麼就需要實現run 方法。

public void run() {    if (target != null) {        target.run();    }}

Thread中的run 方法調用的還是目標任務的run 方法,通過直接調用run 方法並不會建立線程來單獨執行任務,這個我們通過Thread中的run 也可以看出來,要建立線程來執行任務,需要調用Thread的start 方法。 start 方法

/** * Causes this thread to begin execution; the Java Virtual Machine * calls the run method of this thread. */public synchronized void start() {    /**     * This method is not invoked for the main method thread or "system"     * group threads created/set up by the VM. Any new functionality added     * to this method in the future may have to also be added to the VM.     *     * A zero status value corresponds to state "NEW".     */    if (threadStatus != 0) // 如果線程不是初始狀態,那麼會拋出異常        throw new IllegalThreadStateException();    /* Notify the group that this thread is about to be started     * so that it can be added to the group's list of threads     * and the group's unstarted count can be decremented.      */    //將啟動的線程添加到線程組     group.add(this);    boolean started = false;    try {        start0(); //調用本地方法        started = true;    } finally {        try {            if (!started) {                group.threadStartFailed(this);            }        } catch (Throwable ignore) {            /* do nothing. If start0 threw a Throwable then              it will be passed up the call stack */        }    }}private native void start0();

start方法是同步的(synchronized 修飾),在啟動線程前會檢查線程狀態,如果線程不是初始狀態,那麼會拋出異常,因此多次調用start 是不可行的。
start 方法被調用者線程執行,JVM將會調用這個線程的run方法,這樣產生的結果是,兩個線程執行著,其中一個是調用start()方法的線程執行,另一個線程是執行run方法的線程。 sleep()方法

 /**  * Causes the currently executing thread to sleep (temporarily cease  * execution) for the specified number of milliseconds plus the specified  * number of nanoseconds, subject to the precision and accuracy of system  * timers and schedulers. The thread does not lose ownership of any  * monitors.  */ public static void sleep(long millis, int nanos) throws InterruptedException {     if (millis < 0) {         throw new IllegalArgumentException("timeout value is negative");     }     if (nanos < 0 || nanos > 999999) {         throw new IllegalArgumentException(                             "nanosecond timeout value out of range");     }     if (nanos >= 500000 || (nanos != 0 && millis == 0)) {         millis++;     }     sleep(millis);  // 調用本地sleep 方法 }

sleep方法的作用使得當前線程休眠一定的時間,值得注意的是這個期間是不會釋放持有的鎖。

###join()方法

/** * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. */public final synchronized void join(long millis) throws InterruptedException {     long base = System.currentTimeMillis();     long now = 0;     if (millis < 0) {         throw new IllegalArgumentException("timeout value is negative");     }     if (millis == 0) {         //一直等待,直到目標線程結束         while (isAlive()) {             wait(0);         }     } else {         while (isAlive()) {             long delay = millis - now;             if (delay <= 0) {                 break;             }             wait(delay); // 逾時等待             now = System.currentTimeMillis() - base;         }     } }

調用線程通過join方法等待被調用線程任務執行,直到逾時或者終止。 interrupt()方法

public void interrupt() {    if (this != Thread.currentThread())        checkAccess();    // 同步處理    synchronized (blockerLock) {        Interruptible b = blocker;        if (b != null) {            interrupt0();           // Just to set the interrupt flag            b.interrupt(this);            return;        }    }    interrupt0(); //調用本地方法}

interrupt()方法是中斷當前的線程(設定中斷標誌位),線程當檢測到中斷標誌位被設定後,可能會拋出InteruptedExeption, 同時會清除線程的中斷狀態,通常中斷可以作為取消任務的一種比較安全的方式(前提是能響應中斷)。 總結

通過對源碼的簡單分析,瞭解了Thread一些使用方法和注意事項,整個過程對Thread的分析是比較淺顯的,當然對多線程的研究也才剛剛開始,並沒有完全深入各個細節,但是通過源碼的分析,知道了線程整個建立的大致過程,對於使用Thread也會更加得心應手。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.