多線程學(xué)習(xí)筆記
在之前的java開(kāi)發(fā)中一般都是java web方向的工作,對(duì)多線程使用的非常少。了解僅限于Runnable和Thread的區(qū)別與使用。最近在做小工具的時(shí)候用到了多線程,從零開(kāi)始學(xué)習(xí)關(guān)于多線程和并發(fā)方面的知識(shí)。
并發(fā)和多線程之間的關(guān)系
并發(fā)與多線程之間的關(guān)系就是目的與手段之間的關(guān)系。并發(fā)(Concurrent)的反面是串行。并發(fā)的極致就是并行(Parallel)。多線程就是將原本可能是串行的計(jì)算“改為”并發(fā)(并行)的一種手段、途徑或者模型。因此,有時(shí)我們也稱多線程編程為并發(fā)編程。當(dāng)然,目的與手段之間常常是一對(duì)多的關(guān)系。并發(fā)編程還有其他的實(shí)現(xiàn)途徑,多線程編程往往是其他并發(fā)編程模型的基礎(chǔ)。
實(shí)現(xiàn)多線程的方式:1.繼承Thread類,2.實(shí)現(xiàn)Runnable接口。實(shí)際上Thread也是Runnable的一個(gè)子類。使用繼承Thread最大的局限性在于不支持多繼承。所以為了支持多繼承,就會(huì)使用Runnable接口的方式。
Runnable接口就是定義了一個(gè)run方法。所以重點(diǎn)看Thread類。
Thread有9個(gè)構(gòu)造方法。常用的有Thread()和Thread(Runnable)兩個(gè),構(gòu)造方法都調(diào)用了init()方法,初始化一個(gè)線程。
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name.toCharArray();
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* 判斷是否為 applet */
/* 如果有security manager */
if (security != null) {
g = security.getThreadGroup();
}
/* 如果 security manager getThreadGroup 為null*/
if (g == null) {
g = parent.getThreadGroup();
}
}
/* 不管是否是傳入?yún)?shù)的ThreadGroup 都再進(jìn)行security manager 檢查*/
g.checkAccess();
/*
* 權(quán)限控制?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
// 添加在未啟動(dòng)的線程組
g.addUnstarted();
this.group = g;
//是否是守護(hù)線程
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 (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();
}
通過(guò)init(ThreadGroup, Runnable, String, stackSize, AccessControlContext)方法來(lái)完成Thread對(duì)象的創(chuàng)建 整個(gè)過(guò)程是
-
registerNatives()靜態(tài)塊, 判斷name。設(shè)置name,獲取Thread parent,獲取SecurityManager。 - 檢查
security.線程組中的nUnstartedThreads++。 - 設(shè)置
ThreadGroup線程組,設(shè)置daemon是否守護(hù)線程,priority優(yōu)先,ContextClassLoaderclassLoader,inheritedAccessControlContext繼承的訪問(wèn)控制上下文,target為繼承Runnable接口的對(duì)象。inheritableThreadLocalsthreadLocal,stackSize,id設(shè)置。
整個(gè)Thread對(duì)象的創(chuàng)建過(guò)程大概就是這樣一個(gè)流程。