深入瞭解Thread之構造器
xl_echo編輯整理,歡迎轉載,轉載請宣告文章來源。更多IT、程式設計案例、資料請聯絡QQ:1280023003,加群298140694。百戰不敗,依不自稱常勝,百敗不頹,依能奮力前行。——這才是真正的堪稱強大!!
在之前的文章中我們對多執行緒和實現執行緒等基礎知識有了一定的瞭解,這個時候我們就可以繼續深入的瞭解一下執行緒的實現,Thread的構造
Thread的構造
我們可以通過建立一個類,繼承Tread來,然後檢視Tread的底層實現。可以看到Thread類的構造方法被過載了八次,陳列如下:
public Thread(){init(null, null , "Thread-" + nextThreadNum(), 0);};
public Thread(Runnable target){init(null, target, "Thread-" + nextThreadNum(), 0);};
public Thread(String name){init(group, target, "Thread-" + nextThreadNum(), 0);};
public Thread(Runnable target, String name){init(null, null, name, 0);};
public Thread(ThreadGroup group, Runnable target){init(group, null , name, 0);};
public Thread(ThreadGroup group, 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);};
構造方法中幾個引數的作用
- Runnable target
實現了Runnable介面的類的例項。要注意的是Thread類也實現了Runnable介面,因此,從Thread類繼承的類的例項也可以作為target傳入這個構造方法。
- String name
執行緒的名字。這個名字可以在建立Thread例項後通過Thread類的setName方法設定。如果不設定執行緒的名子,執行緒就使用預設的執行緒名:Thread-N,N是執行緒建立的順序自增變數,是一個不重複的正整數。在我們的原始碼中可以看到他的實現:
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
- ThreadGroup group
當前建立的執行緒所屬的執行緒組。如果不指定執行緒組,所有的執行緒都被加到一個預設的執行緒組中。關於執行緒組的細節將在後面的章節詳細討論。
- long stackSize
執行緒棧的大小,這個值一般是CPU頁面的整數倍。如x86的頁面大小是4KB。在x86平臺下,預設的執行緒棧大小是12KB。
執行緒的繼承
在我們之前多執行緒實現中,我們看到輸出結果都有一個main,原因其實很簡單。其實不難看出,一個執行緒的建立時由另外一個執行緒完成的。我們之前的執行緒一開始是隻有main執行緒,main執行緒是JVM建立的,這反證了我們這個觀點。(請不要糾結源頭是誰,這種問題要麼就是進入到雞生蛋蛋生雞的迴圈中去,要麼就是要扯到遠古)
建立執行緒的時候,我們也可以看到我們執行緒的父執行緒。
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == 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. */
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 (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 */
tid = nextThreadID();
}
其中currentThread();
就是在建立新執行緒的時候獲取當前執行緒來做新建的操作。
既然可以繼承,可以到某一個執行緒組裡面,那麼我們就應該可以自己將新執行緒加入到某個執行緒組
我們之前的構造方法當中就有實現我們這個需求的過載方法。只需要在我們建立執行緒的時候,傳入一個ThreadGroup group
就指定了需要計入的執行緒組。