Thread閱讀筆記
問題
一、簡介
它是Java.lang包的一個類,調用系統內核來執行線程
二、繼承關係圖
三、源碼分析
內部類
- 枚舉State類
public enum State {
/**
* 新建狀態:線程剛創建,還未執行start方法
*/
NEW,
/**
* 可運行狀態:已經就緒可運行的狀態,處於此狀態的線程是正在JVM中運行的,
* 但可能再等待操作系統級別的資源,例如CPU時間片
*/
RUNNABLE,
/**
* 阻塞狀態:阻塞等待監視器鎖,處於此狀態的線程正在阻塞等待監視器鎖,
* 以進入一個同步塊/方法,或者再執行完wait()方法後重入同步塊/方法
*/
BLOCKED,
/**
* 等待狀態:執行完Object.wait無超時參數操作,
* 或者 Thread.join無超時參數操作
* 或者 LockSupport.park 操作後,線程進入等待狀態
* 一般在等待狀態的線程在等待其它線程執行特殊操作,例如:、
* 等待其它線程操作Object.notify() 喚醒 或 Object.notifyAll() 喚醒所有
*/
WAITING,
/**
* 等待狀態:Thread.sleep、Object.await待超時時間、Thread.join帶超時時間
* LockSupport.parkNanos、LockSupport.parkUntil這些 操作會使線程進入顯示等待
*/
TIMED_WAITING,
/**
* 終止狀態(線程執行完畢)
*/
TERMINATED;
}
屬性
// 線程名稱
private volatile String name;
// 線程優先級
private int priority;
private Thread threadQ;
private long eetop;
// 是否單步執行這個線程
private boolean single_step;
// 是否爲守護線程
private boolean daemon = false;
// JVM狀態值
private boolean stillborn = false;
// 線程任務
private Runnable target;
// 線程組
private ThreadGroup group;
// 此線程的上下文類裝入器
private ClassLoader contextClassLoader;
// 它封裝的上下文做出系統資源訪問決策
private AccessControlContext inheritedAccessControlContext;
// 自動編號,就是當沒有設置線程名稱的時候,我們看到的thread-0、thread-1
private static int threadInitNumber;
// 線程堆棧空間大小,默認0,
private long stackSize;
// JVM私有狀態,在本機線程終止後仍然存在。
private long nativeParkEventPointer;
// 線程ID
private long tid;
// 用於生成線程ID
private static long threadSeqNumber;
// 線程初始狀態,表示線程尚未啓動
private volatile int threadStatus = 0;
volatile Object parkBlocker;
private volatile Interruptible blocker;
// 用於synchronized關鍵字的實例鎖
private final Object blockerLock = new Object();
// 最小優先級
public final static int MIN_PRIORITY = 1;
// 默認優先級
public final static int NORM_PRIORITY = 5;
// 最大優先級
public final static int MAX_PRIORITY = 10;
/** 線程自身的副本變量值 */
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
構造
/**
* 總共8個公共構造和一個默認訪問權限的構造
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
init(null, null, name, 0);
}
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
init(group, target, name, stackSize);
}
/**
* 構造方法使用到的nextThreadNum函數-獲得全局自動編號
*/
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
/**
* 構造方法使用到的 init 函數-初始化線程
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
/**
* 構造方法使用到的 init 函數-初始化線程,並封裝的上下文做出系統資源訪問策略
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
// 如果名稱爲null 拋出異常
throw new NullPointerException("name cannot be null");
}
// 名稱賦值
this.name = name;
// 獲得當前線程(當前正在運行的線程)
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. */
// 如果安全管理器不爲null,則當前線程組就是優先用管理器指定的線程組
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
// 如果線程組還是爲null 則使用父線程的線程組
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) {
// 如果安全管理器不爲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 */
// 設置指定的堆棧大小
this.stackSize = stackSize;
/* Set thread ID */
// 設置線程Id
tid = nextThreadID();
}
主要方法
1、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();
// 啓動成功,設置爲true
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();
2、run()-運行方法
@Override
public void run() {
if (target != null) {
// 直接調用線程任務
target.run();
}
}
3、exit()-退出方法-私有
private void exit() {
if (group != null) {
// 從線程組中移除自身,並notifyAll()
group.threadTerminated(this);
// 幫助gc
group = null;
}
// 幫忙 GC
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
4、interrupt()-中斷方法
public void interrupt() {
if (this != Thread.currentThread())
// 如果是當前線程,就檢查是否有安全管理器
// 如果有安全管理器就檢查權限
checkAccess();
// 加鎖,中斷blockerLock鎖
synchronized (blockerLock) {
// 設置中斷接口
Interruptible b = blocker;
if (b != null) {
// 設置中斷標記
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
// 調用本地native方法中斷
interrupt0();
}
5、interrupted()-是否已中斷
// 判斷當前運行的線程是否中斷
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
// 判斷線程是否中斷
public boolean isInterrupted() {
return isInterrupted(false);
}
// 本地native方法
private native boolean isInterrupted(boolean ClearInterrupted);
6、isAlive()是否被激活
- 本地方法,
public final native boolean isAlive();
7、yield()-暫停線程
- 暫停一下線程,回到就緒狀態,讓出CPU資源,
public static native void yield();
8、sleep - 2個方法
- 會佔用CPU資源
9、join - 3個方法
- 會釋放CPU資源
// 立即
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis)
throws InterruptedException {
// 加鎖執行
// 設置開始時間
long base = System.currentTimeMillis();
long now = 0;
// 參數效驗,低於0 拋參數異常
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
// 如果millis等於0,則判斷線程是否激活中,
// 如果是就執行native方法Object.wait(0)使其等待
while (isAlive()) {
wait(0);
}
} else {
// 循環判斷線程是否激活,
while (isAlive()) {
// 獲取當前還剩餘延遲時間
long delay = millis - now;
// 如果延遲時間超過了還沒休眠線程,則退出不休眠了
if (delay <= 0) {
break;
}
// 調用native方法Object.wait(delay) 使其等待
wait(delay);
// 更新已用休眠時間
now = System.currentTimeMillis() - base;
}
}
}
public final synchronized void join(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)) {
// 如果納秒 >= 500000 就把毫秒 + 1
// 如果納秒 != 0 && millis == 0 就把毫秒 + 1
millis++;
}
// 調用 join(long millis)
join(millis);
}
補充
無
四、總結
- 利用的操作系統來創建啓動線程,
- 內含線程的啓動、休眠、阻塞、停止、中斷方法,還包含各種線程參數的獲取和判斷參數