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

[toc]

前面已經(jīng)對(duì)java中Thread的生命周期進(jìn)行了分析荤胁,現(xiàn)在看看Thread的源碼。

1.類結(jié)構(gòu)及其成員變量

1.1 類結(jié)構(gòu)

Thread類實(shí)現(xiàn)了Runnable谱净,實(shí)際上我們說過,需要起一個(gè)線程的話擅威,需要繼承Thread或者實(shí)現(xiàn)Runnable接口壕探。實(shí)際上都是實(shí)現(xiàn)了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是程序中執(zhí)行的線程李请,JVM允許在一個(gè)程序中分配多個(gè)線程并發(fā)執(zhí)行。
每個(gè)線程都有一個(gè)優(yōu)先級(jí)厉熟,具有較高優(yōu)先級(jí)的線程優(yōu)先于優(yōu)先級(jí)較低的線程執(zhí)行导盅,每個(gè)線程也可以標(biāo)記為守護(hù)線程,也可以不標(biāo)記為守護(hù)線程揍瑟。當(dāng)運(yùn)行在某個(gè)線程中的代碼創(chuàng)建一個(gè)新的線程的對(duì)象時(shí)白翻,新的線程優(yōu)先級(jí)最初設(shè)置為與創(chuàng)建的線程的優(yōu)先級(jí)相等。當(dāng)且僅當(dāng)創(chuàng)建線程是守護(hù)線程的時(shí)候绢片,被創(chuàng)建的新線程才是守護(hù)線程滤馍。
當(dāng)jvm啟動(dòng)的時(shí)候,通常有一個(gè)單獨(dú)的非守護(hù)線程底循,通常用調(diào)用main方法所在的類命名巢株。java虛擬機(jī)會(huì)繼續(xù)執(zhí)行線程,直到出現(xiàn)如下情況:

  • 運(yùn)行時(shí)Runtime調(diào)用exit方法熙涤,安全管理器允許執(zhí)行退出操作阁苞。
  • 所有不是守護(hù)線程的線程都died,要么從調(diào)用run的方法返回祠挫,要么拋出一個(gè)傳播到run方法之外的異常猬错。

通常有兩種方式創(chuàng)建一個(gè)線程,一種是繼承Thread類茸歧,子類應(yīng)該重寫run方法倦炒。然后子類的實(shí)例是可分配的并啟動(dòng)。例如软瞎,計(jì)算質(zhì)數(shù)的線程大于指定值可寫成:

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

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

然后通過如下代碼來創(chuàng)建線程:

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

創(chuàng)建線程的另外一種方法是申明一個(gè)類實(shí)現(xiàn)Runnable接口逢唤。然后這個(gè)類實(shí)現(xiàn)run方法拉讯。類的實(shí)例在此后分配,在創(chuàng)建時(shí)做為Thread的參數(shù)傳遞給Thread鳖藕,然后啟動(dòng)魔慷,看起來如下所示:

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

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

之后通過如下代碼創(chuàng)建:

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

每個(gè)線程都有一個(gè)用于標(biāo)識(shí)的名稱,超過一個(gè)線程可以有相同的名字著恩,如果名稱未指定時(shí)創(chuàng)建要給線程院尔,將自動(dòng)為其生成一個(gè)新名稱。

1.2 成員變量

其常量區(qū)代碼如下:

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 線程的優(yōu)先級(jí)喉誊,默認(rèn)為5邀摆,范圍1-10
threadQ Thread
eetop long
single_step boolean 是否單步執(zhí)行
daemon boolean 守護(hù)線程狀態(tài),默認(rèn)為false
stillborn boolean JVM狀態(tài)伍茄,默認(rèn)為false
target target 將被執(zhí)行的Runnable實(shí)現(xiàn)類
group ThreadGroup 當(dāng)前線程的線程組
contextClassLoader ClassLoader 這個(gè)線程上下文的類加載器
inheritedAccessControlContext AccessControlContext 該線程繼承的AccessControlContext
threadInitNumber static int 用于匿名線程的自動(dòng)編號(hào)
threadLocals ThreadLocal.ThreadLocalMap 屬于此線程的ThreadLocal,這個(gè)映射關(guān)系通過ThreadLocal維持
inheritableThreadLocals ThreadLocal.ThreadLocalMap 這個(gè)線程的InheritableThreadLocal栋盹,其映射關(guān)系通過InheritableThreadLocal維持
stackSize long 此線程的請(qǐng)求的堆棧的大小,如果創(chuàng)建者的請(qǐng)求堆棧大小為0敷矫,則不指定堆棧大小例获,由jvm來自行決定。一些jvm會(huì)忽略這個(gè)參數(shù)曹仗。
nativeParkEventPointer long 在本機(jī)線程終止后持續(xù)存在的jvm私有狀態(tài)榨汤。
tid long 線程的ID
threadSeqNumber static long 用于生成線程的ID
threadStatus volatile int java線程狀態(tài),0表示未啟動(dòng)
parkBlocker volatile Object 提供給LockSupport調(diào)用的參數(shù)
blocker volatile Interruptible 此線程在可中斷的IO操作中被阻塞的對(duì)象怎茫,阻塞程序的中斷方法應(yīng)該在設(shè)置了這個(gè)線程中斷狀態(tài)之后被調(diào)用

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;

實(shí)際上這些常量值是對(duì)于線程優(yōu)先級(jí)的常量件余,最小為1,最大為10遭居,默認(rèn)值為5。操作系統(tǒng)在線程在運(yùn)行的過程中會(huì)按照優(yōu)先級(jí)來分配時(shí)間片旬渠。

2.構(gòu)造方法

2.1 Thread()

空構(gòu)造函數(shù)俱萍,發(fā)呢配一個(gè)新的Thread對(duì)象,實(shí)際上是調(diào)用的init方法告丢。由于Thread大部分代碼都是native來實(shí)現(xiàn)枪蘑,因此這個(gè)構(gòu)造函數(shù)是通過改變前面的成員變量來實(shí)現(xiàn)對(duì)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啟動(dòng)線程的方法岖免。
實(shí)際上我們穿入的Runnable對(duì)象岳颇,被放置在了target變量中,之后通過后jvm中啟動(dòng)線程|

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的時(shí)候還可以指定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()返回為空瞻鹏,則返回當(dāng)前的線程組悲立。

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

分配一個(gè)線程新博,使其將target做為目標(biāo)對(duì)象薪夕,具有name指定的名稱,和group指定的線程組赫悄。其中原献,指定StackSize參數(shù)能夠決定其for循環(huán)棧的深度,但是這也由JVM決定埂淮,某些JVM這個(gè)參數(shù)并不能生效姑隅。
JVM可以自由的處理stackSize的參數(shù)做為建議值,如果指定的值低得不合理同诫,那么可以使用jvm平臺(tái)的最小值粤策。如果值太高,則可能會(huì)使用平臺(tái)缺省的最大值误窖。虛擬機(jī)可以自由地四舍五入指定的值叮盘,讓到JVM認(rèn)為是合適的值。
stackSize參數(shù)為0則會(huì)導(dǎo)致其與Thread(ThreadGroup, Runnable, String)構(gòu)造器完全一致霹俺。
由于這個(gè)特性依賴于JVM平臺(tái)柔吼,因此在使用的時(shí)候要特別小心,給定線程的stackSize可能因?yàn)榫€程對(duì)峙的大小造成不同JRE實(shí)現(xiàn)有所不同丙唧。鑒于此愈魏,可能需要仔細(xì)調(diào)整堆棧的大小參數(shù),根據(jù)JRE要運(yùn)行程序的實(shí)際情況進(jìn)行調(diào)優(yōu)想际。

3. native方法

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

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

//返回當(dāng)前線程
public static native Thread currentThread();

//當(dāng)前線程在獲取CPU執(zhí)行權(quán)之后牌柄,讓出,之后讓等待隊(duì)列的線程重新競(jìng)爭(zhēng)侧甫。有可能是當(dāng)前線程再次搶到執(zhí)行權(quán)珊佣,也有可能是其他線程。
public static native void yield();

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

//啟動(dòng)
private native void start0();

//測(cè)試某個(gè)值是否被中斷 中斷狀態(tài)根據(jù)傳入的ClearInterrupted值進(jìn)行重置
private native boolean isInterrupted(boolean ClearInterrupted);

//測(cè)試線程是否是存活狀態(tài)
public final native boolean isAlive();

//計(jì)算線程中的堆棧數(shù)披粟,此線程必須被暫停 咒锻,這個(gè)方法已不再建議使用
public native int countStackFrames();


//當(dāng)且僅當(dāng)當(dāng)前線程在指定的對(duì)象上保持監(jiān)視器鎖時(shí),才返回 true守屉。
public static native boolean holdsLock(Object obj);

//導(dǎo)出線程堆棧信息
private native static StackTraceElement[][] dumpThreads(Thread[] threads);

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

//設(shè)置優(yōu)先級(jí)
private native void setPriority0(int newPriority);
//停止
private native void stop0(Object o);
//掛起
private native void suspend0();
//重置
private native void resume0();
//中斷
private native void interrupt0();
//設(shè)置線程名稱
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如果為空惑艇,則返回異常,實(shí)際上name在其他方法中如果不指定會(huì)自動(dòng)生成拇泛,通常為"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

線程啟動(dòng)的方法:

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 {
    //實(shí)際上調(diào)用的native方法
    start0();
    //之后修改start的狀態(tài)
    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

設(shè)置守護(hù)線程狀態(tài):

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

4.4 checkAccess

檢查訪問狀態(tài):

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

4.5 join

join將當(dāng)前運(yùn)行的線程阻塞须板,之后讓join的持有線程執(zhí)行完之后再繼續(xù)執(zhí)行。等待時(shí)間為傳入的參數(shù)兢卵。

public final synchronized void join(long millis)
throws InterruptedException {
    //獲得當(dāng)前時(shí)間
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
    //如果當(dāng)前線程可用习瑰,則調(diào)用wait
        while (isAlive()) {
            wait(0);
        }
    } else {
        通過wait方法delay。
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

這個(gè)方法提供給另外兩個(gè)方法調(diào)用:

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

其中wait(0)的話秽荤,則會(huì)一直阻塞甜奄,直到notify才會(huì)返回。不難發(fā)現(xiàn)窃款,join方法底層實(shí)際上是wait方法课兄。

4.6 sleep

sleep方法通過native方法實(shí)現(xiàn)晨继。

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();
   鎖定之后調(diào)用interrupt0
    synchronized (blockerLock) {
        Interruptible b = blocker;
        //如果b不為null則返回
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    //當(dāng)b為空的情況確保interrupt0一定會(huì)被執(zhí)行蜒茄。
    interrupt0();
}

4.8 stop方法

stop方法已經(jīng)過時(shí),不再采用這個(gè)方法停止線程檀葛,這是因?yàn)楦顾酰瑂top方法非常粗暴屿聋,會(huì)導(dǎo)致很多問題,后面詳細(xì)分析藏鹊。

@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.內(nèi)部類

5.1 Caches

cache緩存了子類安全審計(jì)的結(jié)果。如果未來要進(jìn)行使用楚殿,采用ConcurrentReferenceHashMap替換宴抚。

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

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

5.2 WeakClassKey

弱引用對(duì)象的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

線程的狀態(tài)內(nèi)部枚舉類常潮。這個(gè)線程的狀態(tài)有NEW楷力、RUNNABLE孵户、BLOCKED夏哭、WAITING献联、TIMED_WAITING、TERMINATED狀態(tài)进胯。

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

狀態(tài)的詳細(xì)描述在前面文章中已經(jīng)詳細(xì)介紹。我們重點(diǎn)需要關(guān)注這些狀態(tài)的轉(zhuǎn)換:


線程模型

6.總結(jié)

本文分析了Thread的源碼盯漂。我們可以看出署隘,實(shí)際上join方法實(shí)際上底層是采用了synchronized和Object的wait方法。另外违崇,停止線程的stop方法已經(jīng)棄用诊霹,我們應(yīng)該用interrupt()方法。
stop和interrupt方法區(qū)別在于:
stop方法會(huì)立即殺死線程伴箩,不給線程任何暫停的機(jī)會(huì)鄙漏,一旦線程持有Lock怔蚌,那么線程就來不及調(diào)用unlock方法,這樣就導(dǎo)致其他線程再也不可能獲得這個(gè)鎖椅野。這是非常危險(xiǎn)的操作,也是為什么stop方法會(huì)被棄用的原因离福。
interrupt方法則僅僅只是通知線程炼蛤,線程可以繼續(xù)執(zhí)行后續(xù)操作,interrupt實(shí)際上是一個(gè)異常檢測(cè)的流程赠涮。當(dāng)線程 處于 WAITING暗挑、TIMED_WAITING 狀態(tài)時(shí)炸裆,如果其他線程調(diào)用線程的 interrupt() 方法,會(huì)使線程返回到 RUNNABLE 狀態(tài)国拇,同時(shí)線程 的代碼會(huì)觸發(fā) InterruptedException 異常惯殊。
此外還有一種主動(dòng)檢測(cè)機(jī)制,就是通過調(diào)用isInterrupted()方法务热。
最后己儒,我們需要重點(diǎn)掌握線程模型中的6個(gè)狀態(tài)及其轉(zhuǎn)換的過程闪湾。這也是我們學(xué)習(xí)線程的重點(diǎn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末江醇,一起剝皮案震驚了整個(gè)濱河市何暇,隨后出現(xiàn)的幾起案子赖晶,更是在濱河造成了極大的恐慌,老刑警劉巖捂贿,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胳嘲,死亡現(xiàn)場(chǎng)離奇詭異了牛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)甫窟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門粗井,熙熙樓的掌柜王于貴愁眉苦臉地迎上來街图,“玉大人,你說我怎么就攤上這事耘擂⌒跄罚” “怎么了滚朵?”我有些...
    開封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)韵吨。 經(jīng)常有香客問我移宅,道長(zhǎng)漏峰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任倔喂,我火速辦了婚禮席噩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘埠忘。我一直安慰自己馒索,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開白布旨怠。 她就那樣靜靜地躺著运吓,像睡著了一般疯趟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上倦青,一...
    開封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天产镐,我揣著相機(jī)與錄音踢步,去河邊找鬼。 笑死述雾,一個(gè)胖子當(dāng)著我的面吹牛兼丰,可吹牛的內(nèi)容都是我干的鳍征。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼匣掸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼碰酝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤碱璃,失蹤者是張志新(化名)和其女友劉穎饭入,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爽航,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡讥珍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年衷佃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蹄葱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖竣况,靈堂內(nèi)的尸體忽然破棺而出丹泉,到底是詐尸還是另有隱情嘀掸,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布泉蝌,位于F島的核電站勋陪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏寒锚。R本人自食惡果不足惜违孝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一雌桑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拣技,春花似錦耍目、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽俺抽。三九已至,卻和暖如春振愿,著一層夾襖步出監(jiān)牢的瞬間弛饭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憔晒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓攻询,卻偏偏與公主長(zhǎng)得像州弟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拯杠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359