文章目錄 - 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.總結
- 1.1 類結構
- 1.2 成員變量
- 1.3 常量
- 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)
- 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.1 Caches
- 5.2 WeakClassKey
- 5.3 State
前面已經對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
* . . .
* }
* }
* </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
* . . .
* }
* }
* </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
. . .
}
}
複制
然後通過如下代碼來建立線程:
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
. . .
}
}
複制
之後通過如下代碼建立:
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;
}
複制
狀态的較長的描述在前面文章中已經詳細介紹。我們重點需要關注這些狀态的轉換:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAjM2EzLcd3LcJzLcJzdllmVldWYtl2Pn5GcuQWay1GevlWetZ3LcNjMyQjM3czLcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
6.總結
本文分析了Thread的源碼。我們可以看出,實際上join方法實際上底層是采用了synchronized和Object的wait方法。另外,停止線程的stop方法已經棄用,我們應該用interrupt()方法。
stop和interrupt方法差別在于:
stop方法會立即殺死線程,不給線程任何暫停的機會,一旦線程持有Lock,那麼線程就來不及調用unlock方法,這樣就導緻其他線程再也不可能獲得這個鎖。這是非常危險的操作,也是為什麼stop方法會被棄用的原因。
interrupt方法則僅僅隻是通知線程,線程可以繼續執行後續操作,interrupt實際上是一個異常檢測的流程。當線程 處于 WAITING、TIMED_WAITING 狀态時,如果其他線程調用線程的 interrupt() 方法,會使線程傳回到 RUNNABLE 狀态,同時線程 的代碼會觸發 InterruptedException 異常。
此外還有一種主動檢測機制,就是通過調用isInterrupted()方法。
最後,我們需要重點掌握線程模型中的6個狀态及其轉換的過程。這也是我們學習線程的重點。