天天看點

多線程基礎(二): Thread源碼分析

文章目錄
  • 1.類結構及其成員變量
    • 1.1 類結構
    • 1.2 成員變量
    • 1.3 常量
  • 2.構造方法
    • 2.1 Thread()
    • 2.2 Thread(Runnable target)
    • 2.3 Thread(Runnable target, AccessControlContext acc)
    • 2.4 Thread(ThreadGroup group, Runnable target)
    • 2.5 Thread(String name)
    • 2.6 Thread(ThreadGroup group, String name)
    • 2.7 Thread(Runnable target, String name)
    • 2.8 Thread(ThreadGroup group, Runnable target, String name)
    • 2.9 Thread(ThreadGroup group, Runnable target, String name,long stackSize)
  • 3. native方法
  • 4.重要的非native方法
    • 4.1 init
    • 4.2 start
    • 4.3 setDaemon
    • 4.4 checkAccess
    • 4.5 join
    • 4.6 sleep
    • 4.7 interrupt
    • 4.8 stop方法
  • 5.内部類
    • 5.1 Caches
    • 5.2 WeakClassKey
    • 5.3 State
  • 6.總結

前面已經對java中Thread的生命周期進行了分析,現在看看Thread的源碼。

1.類結構及其成員變量

1.1 類結構

Thread類實作了Runnable,實際上我們說過,需要起一個線程的話,需要繼承Thread或者實作Runnable接口。實際上都是實作了Runnable接口。

/**
 * A <i>thread</i> is a thread of execution in a program. The Java
 * Virtual Machine allows an application to have multiple threads of
 * execution running concurrently.
 * <p>
 * Every thread has a priority. Threads with higher priority are
 * executed in preference to threads with lower priority. Each thread
 * may or may not also be marked as a daemon. When code running in
 * some thread creates a new <code>Thread</code> object, the new
 * thread has its priority initially set equal to the priority of the
 * creating thread, and is a daemon thread if and only if the
 * creating thread is a daemon.
 * <p>
 * When a Java Virtual Machine starts up, there is usually a single
 * non-daemon thread (which typically calls the method named
 * <code>main</code> of some designated class). The Java Virtual
 * Machine continues to execute threads until either of the following
 * occurs:
 * <ul>
 * <li>The <code>exit</code> method of class <code>Runtime</code> has been
 *     called and the security manager has permitted the exit operation
 *     to take place.
 * <li>All threads that are not daemon threads have died, either by
 *     returning from the call to the <code>run</code> method or by
 *     throwing an exception that propagates beyond the <code>run</code>
 *     method.
 * </ul>
 * <p>
 * There are two ways to create a new thread of execution. One is to
 * declare a class to be a subclass of <code>Thread</code>. This
 * subclass should override the <code>run</code> method of class
 * <code>Thread</code>. An instance of the subclass can then be
 * allocated and started. For example, a thread that computes primes
 * larger than a stated value could be written as follows:
 * <hr><blockquote><pre>
 *     class PrimeThread extends Thread {
 *         long minPrime;
 *         PrimeThread(long minPrime) {
 *             this.minPrime = minPrime;
 *         }
 *
 *         public void run() {
 *             // compute primes larger than minPrime
 *             &nbsp;.&nbsp;.&nbsp;.
 *         }
 *     }
 * </pre></blockquote><hr>
 * <p>
 * The following code would then create a thread and start it running:
 * <blockquote><pre>
 *     PrimeThread p = new PrimeThread(143);
 *     p.start();
 * </pre></blockquote>
 * <p>
 * The other way to create a thread is to declare a class that
 * implements the <code>Runnable</code> interface. That class then
 * implements the <code>run</code> method. An instance of the class can
 * then be allocated, passed as an argument when creating
 * <code>Thread</code>, and started. The same example in this other
 * style looks like the following:
 * <hr><blockquote><pre>
 *     class PrimeRun implements Runnable {
 *         long minPrime;
 *         PrimeRun(long minPrime) {
 *             this.minPrime = minPrime;
 *         }
 *
 *         public void run() {
 *             // compute primes larger than minPrime
 *             &nbsp;.&nbsp;.&nbsp;.
 *         }
 *     }
 * </pre></blockquote><hr>
 * <p>
 * The following code would then create a thread and start it running:
 * <blockquote><pre>
 *     PrimeRun p = new PrimeRun(143);
 *     new Thread(p).start();
 * </pre></blockquote>
 * <p>
 * Every thread has a name for identification purposes. More than
 * one thread may have the same name. If a name is not specified when
 * a thread is created, a new name is generated for it.
 * <p>
 * Unless otherwise noted, passing a {@code null} argument to a constructor
 * or method in this class will cause a {@link NullPointerException} to be
 * thrown.
 *
 * @author  unascribed
 * @see     Runnable
 * @see     Runtime#exit(int)
 * @see     #run()
 * @see     #stop()
 * @since   JDK1.0
 */
public
class Thread implements Runnable {
    
}           

複制

如上是Thread的源碼。

其注釋大意為:thread是程式中執行的線程,JVM允許在一個程式中配置設定多個線程并發執行。

每個線程都有一個優先級,具有較高優先級的線程優先于優先級較低的線程執行,每個線程也可以标記為守護線程,也可以不标記為守護線程。當運作在某個線程中的代碼建立一個新的線程的對象時,新的線程優先級最初設定為與建立的線程的優先級相等。當且僅當建立線程是守護線程的時候,被建立的新線程才是守護線程。

當jvm啟動的時候,通常有一個單獨的非守護線程,通常用調用main方法所在的類命名。java虛拟機會繼續執行線程,直到出現如下情況:

  • 運作時Runtime調用exit方法,安全管理器允許執行退出操作。
  • 所有不是守護線程的線程都died,要麼從調用run的方法傳回,要麼抛出一個傳播到run方法之外的異常。

通常有兩種方式建立一個線程,一種是繼承Thread類,子類應該重寫run方法。然後子類的執行個體是可配置設定的并啟動。例如,計算質數的線程大于指定值可寫成:

class PrimeThread extends Thread {
    long minPrime;
    PrimeThread(long minPrime) {
         this.minPrime = minPrime;
     }

   public void run() {
        // compute primes larger than minPrime
       &nbsp;.&nbsp;.&nbsp;.
     }
}           

複制

然後通過如下代碼來建立線程:

PrimeThread p = new PrimeThread(143);
p.start();           

複制

建立線程的另外一種方法是申明一個類實作Runnable接口。然後這個類實作run方法。類的執行個體在此後配置設定,在建立時做為Thread的參數傳遞給Thread,然後啟動,看起來如下所示:

class PrimeRun implements Runnable {
   long minPrime;
   PrimeRun(long minPrime) {
       this.minPrime = minPrime;
   }

  public void run() {
       // compute primes larger than minPrime
       &nbsp;.&nbsp;.&nbsp;.
   }
}           

複制

之後通過如下代碼建立:

PrimeRun p = new PrimeRun(143);
 new Thread(p).start();           

複制

每個線程都有一個用于辨別的名稱,超過一個線程可以有相同的名字,如果名稱未指定時建立要給線程,将自動為其生成一個新名稱。

1.2 成員變量

其常量區代碼如下:

private volatile String name;
private int            priority;
private Thread         threadQ;
private long           eetop;

/* Whether or not to single_step this thread. */
private boolean     single_step;

/* Whether or not the thread is a daemon thread. */
private boolean     daemon = false;

/* JVM state */
private boolean     stillborn = false;

/* What will be run. */
private Runnable target;

/* The group of this thread */
private ThreadGroup group;

/* The context ClassLoader for this thread */
private ClassLoader contextClassLoader;

/* The inherited AccessControlContext of this thread */
private AccessControlContext inheritedAccessControlContext;

/* For autonumbering anonymous threads. */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
    return threadInitNumber++;
}

/* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
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.
 */
private long stackSize;

/*
 * JVM-private state that persists after native thread termination.
 */
private long nativeParkEventPointer;

/*
 * Thread 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;


private static synchronized long nextThreadID() {
    return ++threadSeqNumber;
}

/**
 * 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;           

複制

其主要成員變量如下:

變量名 類型 說明
name volatile String 線程名稱
priority int 線程的優先級,預設為5,範圍1-10
threadQ Thread
eetop long
single_step boolean 是否單步執行
daemon boolean 守護線程狀态,預設為false
stillborn boolean JVM狀态,預設為false
target target 将被執行的Runnable實作類
group ThreadGroup 目前線程的線程組
contextClassLoader ClassLoader 這個線程上下文的類加載器
inheritedAccessControlContext AccessControlContext 該線程繼承的AccessControlContext
threadInitNumber static int 用于匿名線程的自動編号
threadLocals ThreadLocal.ThreadLocalMap 屬于此線程的ThreadLocal,這個映射關系通過ThreadLocal維持
inheritableThreadLocals ThreadLocal.ThreadLocalMap 這個線程的InheritableThreadLocal,其映射關系通過InheritableThreadLocal維持
stackSize long 此線程的請求的堆棧的大小,如果建立者的請求堆棧大小為0,則不指定堆棧大小,由jvm來自行決定。一些jvm會忽略這個參數。
nativeParkEventPointer long 在本機線程終止後持續存在的jvm私有狀态。
tid long 線程的ID
threadSeqNumber static long 用于生成線程的ID
threadStatus volatile int java線程狀态,0表示未啟動
parkBlocker volatile Object 提供給LockSupport調用的參數
blocker volatile Interruptible 此線程在可中斷的IO操作中被阻塞的對象,阻塞程式的中斷方法應該在設定了這個線程中斷狀态之後被調用

1.3 常量

/**
 * The minimum priority that a thread can have.
 */
public final static int MIN_PRIORITY = 1;

/**
 * The default priority that is assigned to a thread.
 */
public final static int NORM_PRIORITY = 5;

/**
 * The maximum priority that a thread can have.
 */
public final static int MAX_PRIORITY = 10;           

複制

實際上這些常量值是對于線程優先級的常量,最小為1,最大為10,預設值為5。作業系統線上程在運作的過程中會按照優先級來配置設定時間片。

2.構造方法

2.1 Thread()

空構造函數,發呢配一個新的Thread對象,實際上是調用的init方法。由于Thread大部分代碼都是native來實作,是以這個構造函數是通過改變前面的成員變量來實作對Thread各種行為的改變。

/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (null, null, 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.
 */
public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}           

複制

2.2 Thread(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(), 0);
}           

複制

此方法是我們通常用Runnable啟動線程的方法。

實際上我們穿入的Runnable對象,被放置在了target變量中,之後通過後jvm中啟動線程|

2.3 Thread(Runnable target, AccessControlContext acc)

/**
 * Creates a new Thread that inherits the given AccessControlContext.
 * This is not a public constructor.
 */
Thread(Runnable target, AccessControlContext acc) {
    init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}           

複制

在傳入Runnable的時候還可以指定AccessControlContext。

2.4 Thread(ThreadGroup group, Runnable target)

/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (group, 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  group
 *         the thread group. If {@code null} and there is a security
 *         manager, the group is determined by {@linkplain
 *         SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
 *         If there is not a security manager or {@code
 *         SecurityManager.getThreadGroup()} returns {@code null}, the group
 *         is set to the current thread's thread group.
 *
 * @param  target
 *         the object whose {@code run} method is invoked when this thread
 *         is started. If {@code null}, this thread's run method is invoked.
 *
 * @throws  SecurityException
 *          if the current thread cannot create a thread in the specified
 *          thread group
 */
public Thread(ThreadGroup group, Runnable target) {
    init(group, target, "Thread-" + nextThreadNum(), 0);
}           

複制

使用線程組ThreadGroup。如果有安全管理器,則線程由安全管理器傳回 SecurityManager.getThreadGroup()。如果沒有安全管理器或者SecurityManager.getThreadGroup()傳回為空,則傳回目前的線程組。

2.5 Thread(String name)

指定線程的名稱:

/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (null, null, name)}.
 *
 * @param   name
 *          the name of the new thread
 */
public Thread(String name) {
    init(null, null, name, 0);
}           

複制

2.6 Thread(ThreadGroup group, String name)

/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (group, null, name)}.
 *
 * @param  group
 *         the thread group. If {@code null} and there is a security
 *         manager, the group is determined by {@linkplain
 *         SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
 *         If there is not a security manager or {@code
 *         SecurityManager.getThreadGroup()} returns {@code null}, the group
 *         is set to the current thread's thread group.
 *
 * @param  name
 *         the name of the new thread
 *
 * @throws  SecurityException
 *          if the current thread cannot create a thread in the specified
 *          thread group
 */
public Thread(ThreadGroup group, String name) {
    init(group, null, name, 0);
}           

複制

2.7 Thread(Runnable target, String name)

/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (null, target, name)}.
 *
 * @param  target
 *         the object whose {@code run} method is invoked when this thread
 *         is started. If {@code null}, this thread's run method is invoked.
 *
 * @param  name
 *         the name of the new thread
 */
public Thread(Runnable target, String name) {
    init(null, target, name, 0);
}           

複制

通過Runnable并指定線程的name。

2.8 Thread(ThreadGroup group, Runnable target, String name)

public Thread(ThreadGroup group, Runnable target, String name) {
    init(group, target, name, 0);
}           

複制

2.9 Thread(ThreadGroup group, Runnable target, String name,long stackSize)

public Thread(ThreadGroup group, Runnable target, String name,
              long stackSize) {
    init(group, target, name, stackSize);
}           

複制

配置設定一個線程,使其将target做為目标對象,具有name指定的名稱,和group指定的線程組。其中,指定StackSize參數能夠決定其for循環棧的深度,但是這也由JVM決定,某些JVM這個參數并不能生效。

JVM可以自由的處理stackSize的參數做為建議值,如果指定的值低得不合理,那麼可以使用jvm平台的最小值。如果值太高,則可能會使用平台預設的最大值。虛拟機可以自由地四舍五入指定的值,讓到JVM認為是合适的值。

stackSize參數為0則會導緻其與Thread(ThreadGroup, Runnable, String)構造器完全一緻。

由于這個特性依賴于JVM平台,是以在使用的時候要特别小心,給定線程的stackSize可能因為線程對峙的大小造成不同JRE實作有所不同。鑒于此,可能需要仔細調整堆棧的大小參數,根據JRE要運作程式的實際情況進行調優。

3. native方法

由于Thread大部分邏輯都是由JVM完成,是以核心的方法都是native方法。

//確定registerNatives是<clinit>做的第一件事,這個代碼要放在代碼的最前面。
private static native void registerNatives();

//傳回目前線程
public static native Thread currentThread();

//目前線程在擷取CPU執行權之後,讓出,之後讓等待隊列的線程重新競争。有可能是目前線程再次搶到執行權,也有可能是其他線程。
public static native void yield();

//休眠
public static native void sleep(long millis) throws InterruptedException;

//啟動
private native void start0();

//測試某個值是否被中斷 中斷狀态根據傳入的ClearInterrupted值進行重置
private native boolean isInterrupted(boolean ClearInterrupted);

//測試線程是否是存活狀态
public final native boolean isAlive();

//計算線程中的堆棧數,此線程必須被暫停 ,這個方法已不再建議使用
public native int countStackFrames();


//當且僅當目前線程在指定的對象上保持螢幕鎖時,才傳回 true。
public static native boolean holdsLock(Object obj);

//導出線程堆棧資訊
private native static StackTraceElement[][] dumpThreads(Thread[] threads);

//get線程
private native static Thread[] getThreads();

//設定優先級
private native void setPriority0(int newPriority);
//停止
private native void stop0(Object o);
//挂起
private native void suspend0();
//重置
private native void resume0();
//中斷
private native void interrupt0();
//設定線程名稱
private native void setNativeName(String name);           

複制

4.重要的非native方法

4.1 init

線程初始化方法

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals) {
   //name如果為空,則傳回異常,實際上name在其他方法中如果不指定會自動生成,通常為"Thread-" + nextThreadNum()
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }

    this.name = name;
    //指定父線程
    Thread parent = currentThread();
    //安全管理器
    SecurityManager security = System.getSecurityManager();
    //如果線程組為null
    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的線程組
            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 (inheritThreadLocals && parent.inheritableThreadLocals != null)
        this.inheritableThreadLocals =
            ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    /* Stash the specified stack size in case the VM cares */
    //指定stackSize
    this.stackSize = stackSize;

    /* Set thread ID */
    //指定線程id
    tid = nextThreadID();
}           

複制

4.2 start

線程啟動的方法:

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 {
    //實際上調用的native方法
    start0();
    //之後修改start的狀态
    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 */
    }
}
}           

複制

4.3 setDaemon

設定守護線程狀态:

public final void setDaemon(boolean on) {
    checkAccess();
    if (isAlive()) {
        throw new IllegalThreadStateException();
    }
    daemon = on;
}           

複制

4.4 checkAccess

檢查通路狀态:

public final void checkAccess() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkAccess(this);
    }
}           

複制

4.5 join

join将目前運作的線程阻塞,之後讓join的持有線程執行完之後再繼續執行。等待時間為傳入的參數。

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) {
    //如果目前線程可用,則調用wait
        while (isAlive()) {
            wait(0);
        }
    } else {
        通過wait方法delay。
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}           

複制

這個方法提供給另外兩個方法調用:

public final synchronized void join(long millis, int nanos) throws InterruptedException;
 public final void join() throws InterruptedException;           

複制

其中wait(0)的話,則會一直阻塞,直到notify才會傳回。不難發現,join方法底層實際上是wait方法。

4.6 sleep

sleep方法通過native方法實作。

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);
}           

複制

其中隻是判斷了值的範圍。

4.7 interrupt

public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();
   鎖定之後調用interrupt0
    synchronized (blockerLock) {
        Interruptible b = blocker;
        //如果b不為null則傳回
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    //當b為空的情況確定interrupt0一定會被執行。
    interrupt0();
}           

複制

4.8 stop方法

stop方法已經過時,不再采用這個方法停止線程,這是因為,stop方法非常粗暴,會導緻很多問題,後面詳細分析。

@Deprecated
public final void stop() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        checkAccess();
        if (this != Thread.currentThread()) {
            security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
        }
    }
    // A zero status value corresponds to "NEW", it can't change to
    // not-NEW because we hold the lock.
    if (threadStatus != 0) {
        resume(); // Wake up thread if it was suspended; no-op otherwise
    }

    // The VM can handle all thread states
    stop0(new ThreadDeath());
}           

複制

5.内部類

5.1 Caches

cache緩存了子類安全審計的結果。如果未來要進行使用,采用ConcurrentReferenceHashMap替換。

/** cache of subclass security audit results */
/* Replace with ConcurrentReferenceHashMap when/if it appears in a future
 * release */
private static class Caches {
    //緩存子類安全審計結果
    /** cache of subclass security audit results */
    static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
        new ConcurrentHashMap<>();

    //對審計子類的weak引用進行排隊
    /** queue for WeakReferences to audited subclasses */
    static final ReferenceQueue<Class<?>> subclassAuditsQueue =
        new ReferenceQueue<>();
}           

複制

5.2 WeakClassKey

弱引用對象的key。

/**
 *  Weak key for Class objects.
 **/
static class WeakClassKey extends WeakReference<Class<?>> {
    /**
     * saved value of the referent's identity hash code, to maintain
     * a consistent hash code after the referent has been cleared
     */
    private final int hash;

    /**
     * Create a new WeakClassKey to the given object, registered
     * with a queue.
     */
    WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
        super(cl, refQueue);
        hash = System.identityHashCode(cl);
    }

    /**
     * Returns the identity hash code of the original referent.
     */
    @Override
    public int hashCode() {
        return hash;
    }

    /**
     * Returns true if the given object is this identical
     * WeakClassKey instance, or, if this object's referent has not
     * been cleared, if the given object is another WeakClassKey
     * instance with the identical non-null referent as this one.
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;

        if (obj instanceof WeakClassKey) {
            Object referent = get();
            return (referent != null) &&
                   (referent == ((WeakClassKey) obj).get());
        } else {
            return false;
        }
    }
}           

複制

5.3 State

線程的狀态内部枚舉類。這個線程的狀态有NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED狀态。

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
     * {@link Object#wait() Object.wait}.
     */
    BLOCKED,

    /**
     * Thread state for a waiting thread.
     * A thread is in the waiting state due to calling one of the
     * following methods:
     * <ul>
     *   <li>{@link Object#wait() Object.wait} with no timeout</li>
     *   <li>{@link #join() Thread.join} with no timeout</li>
     *   <li>{@link LockSupport#park() LockSupport.park}</li>
     * </ul>
     *
     * <p>A thread in the waiting state is waiting for another thread to
     * perform a particular action.
     *
     * For example, a thread that has called <tt>Object.wait()</tt>
     * on an object is waiting for another thread to call
     * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
     * that object. A thread that has called <tt>Thread.join()</tt>
     * is waiting for a specified thread to terminate.
     */
    WAITING,

    /**
     * Thread state for a waiting thread with a specified waiting time.
     * A thread is in the timed waiting state due to calling one of
     * the following methods with a specified positive waiting time:
     * <ul>
     *   <li>{@link #sleep Thread.sleep}</li>
     *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
     *   <li>{@link #join(long) Thread.join} with timeout</li>
     *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
     *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
     * </ul>
     */
    TIMED_WAITING,

    /**
     * Thread state for a terminated thread.
     * The thread has completed execution.
     */
    TERMINATED;
}           

複制

狀态的較長的描述在前面文章中已經詳細介紹。我們重點需要關注這些狀态的轉換:

多線程基礎(二): Thread源碼分析

6.總結

本文分析了Thread的源碼。我們可以看出,實際上join方法實際上底層是采用了synchronized和Object的wait方法。另外,停止線程的stop方法已經棄用,我們應該用interrupt()方法。

stop和interrupt方法差別在于:

stop方法會立即殺死線程,不給線程任何暫停的機會,一旦線程持有Lock,那麼線程就來不及調用unlock方法,這樣就導緻其他線程再也不可能獲得這個鎖。這是非常危險的操作,也是為什麼stop方法會被棄用的原因。

interrupt方法則僅僅隻是通知線程,線程可以繼續執行後續操作,interrupt實際上是一個異常檢測的流程。當線程 處于 WAITING、TIMED_WAITING 狀态時,如果其他線程調用線程的 interrupt() 方法,會使線程傳回到 RUNNABLE 狀态,同時線程 的代碼會觸發 InterruptedException 異常。

此外還有一種主動檢測機制,就是通過調用isInterrupted()方法。

最後,我們需要重點掌握線程模型中的6個狀态及其轉換的過程。這也是我們學習線程的重點。