摘要:中斷狀態(tài)可以通過來讀取,并且可以通過一個名為的操作讀取和清除。中斷的協(xié)作特性所帶來的一個好處是,它為安全地構(gòu)造可取消活動提供更大的靈活性。中斷允許一個可取消活動來清理正在進行的工作,恢復(fù)不變量,通知其他活動它要被取消,然后才終止。
Thread實現(xiàn)Runnable接口
1.Thread內(nèi)部有個State枚舉,標(biāo)示著線程的狀態(tài)。NEW,新建未開始
RUNNABLE,可執(zhí)行
BLOCKED,阻塞狀態(tài),等待一個monitor lock,或者Object.wait()之后重入一個synchronized鎖定的代碼
WAITING,等待狀態(tài),Object.wait(),Thread.join(),LockSupport.park()之后進入此狀態(tài)
TIMED_WAITING,帶超時時間的等待狀態(tài),Object.wait(long),Thread.join(long),LockSupport.parkNanos(),LockSupport.parkUntil()之后進入此狀態(tài)
TERMINATED,終止?fàn)顟B(tài)
2.接著看下Thread的構(gòu)造函數(shù)及其幾個相關(guān)的成員變量/* 帶目標(biāo)run對象. */ private Runnable target; /* 線程組 */ private ThreadGroup group; /* 此線程的類加載器 */ private ClassLoader contextClassLoader; /* 想要的棧大小,為0時此參數(shù)被忽略,且有VM不支持此參數(shù) */ private long stackSize; /* 狀態(tài)標(biāo)識,0代表新建未開始*/ private volatile int threadStatus = 0; /* 靜態(tài)native方法,返回當(dāng)前線程*/ public static native Thread currentThread(); 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); } 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); } /** * Initializes a Thread. * * @param g 線程組 * @param target 要執(zhí)行的帶run的目標(biāo)對象 * @param name 線程名 * @param stackSize 新線程的棧大小,等于0時可忽略此參數(shù) * @param acc 接入控制上下文 */ 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; Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); //獲取線程組 if (g == null) { /* 從SecurityManager拿線程組 */ if (security != null) { g = security.getThreadGroup(); } /* 如果還沒拿到從當(dāng)前線程拿*/ if (g == null) { g = parent.getThreadGroup(); } } /* 檢查是否可獲取 */ g.checkAccess(); /* * 還是權(quán)限控制檢查 */ 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); //從父線程繼承可繼承的ThreadLocal if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); this.stackSize = stackSize; /* 設(shè)置線程ID */ tid = nextThreadID(); }
不同的構(gòu)造函數(shù)很多,最終都調(diào)init方法,init主要實現(xiàn)的就是把相應(yīng)的參數(shù)放入成員變量里,ThreadGroup的獲取,接入控制,inheritableThreadLocals父繼承,線程id自增。
3.調(diào)用線程執(zhí)行的主方法start及run方法/* 線程啟動方法 */ public synchronized void start() { /** * 如果線程不是NEW狀態(tài),則拋異常 */ if (threadStatus != 0) throw new IllegalThreadStateException(); /* 通知線程組此線程準(zhǔn)備運行里,所以它可以加入到線程組列表中,線程組的未開始數(shù)量可以減少了 */ group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /*什么都不做,如果start0排除一個異常,它已經(jīng)可以被調(diào)用棧知道 */ } } } private native void start0();
start方法主要也是native實現(xiàn),真正開始之前校驗了狀態(tài),并接入ThreadGroup管理。
/* Runnale 接口的方法*/ @Override public void run() { if (target != null) { target.run(); } }
真正的run其實是目標(biāo)類的run方法
4.join方法,等待線程掛掉的方法,會拋出InterruptedException/*如果這個線程還活著就一直等待*/ public final void join() throws InterruptedException { join(0); } /*如果這個線程還活著就一直等待millis時間*/ 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) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
Thread里為數(shù)不多的純Java代碼,它被synchronized標(biāo)記,實現(xiàn)主要是自旋方法檢驗線程是否活著,如果活著,則wait釋放鎖,還有疑問請移步j(luò)oin的討論
6.sleep方法,native實現(xiàn),會拋出InterruptedException/* 睡眠指定毫秒,并不釋放monitor*/ public static native void sleep(long millis) throws InterruptedException;7.yield方法,native實現(xiàn)
/*使當(dāng)前線程從執(zhí)行狀態(tài)(運行狀態(tài))變?yōu)榭蓤?zhí)行態(tài)(就緒狀態(tài))。cpu會從眾多的可執(zhí)行態(tài)里選擇,也就是說,當(dāng)前也就是剛剛的那個線程還是有可能會被再次執(zhí)行到的,并不是說一定會執(zhí)行其他線程而該線程在下一次中不會執(zhí)行到了*/ public static native void yield();7.interrupt方法,更多關(guān)于中斷的請見處理中斷
每個線程都有一個與之相關(guān)聯(lián)的 Boolean 屬性,用于表示線程的中斷狀態(tài)(interrupted status)。中斷狀態(tài)初始時為 false;當(dāng)另一個線程通過調(diào)用 Thread.interrupt() 中斷一個線程時,會出現(xiàn)以下兩種情況之一。如果那個線程在執(zhí)行一個低級可中斷阻塞方法,例如 Thread.sleep()、 Thread.join() 或 Object.wait(),那么它將取消阻塞并拋出 InterruptedException。否則, interrupt() 只是設(shè)置線程的中斷狀態(tài)。 在被中斷線程中運行的代碼以后可以輪詢中斷狀態(tài),看看它是否被請求停止正在做的事情。中斷狀態(tài)可以通過 Thread.isInterrupted() 來讀取,并且可以通過一個名為 Thread.interrupted() 的操作讀取和清除。
中斷是一種協(xié)作機制。當(dāng)一個線程中斷另一個線程時,被中斷的線程不一定要立即停止正在做的事情。相反,中斷是禮貌地請求另一個線程在它愿意并且方便的時候停止它正在做的事情。有些方法,例如 Thread.sleep(),很認(rèn)真地對待這樣的請求,但每個方法不是一定要對中斷作出響應(yīng)。對于中斷請求,不阻塞但是仍然要花較長時間執(zhí)行的方法可以輪詢中斷狀態(tài),并在被中斷的時候提前返回。 您可以隨意忽略中斷請求,但是這樣做的話會影響響應(yīng)。
中斷的協(xié)作特性所帶來的一個好處是,它為安全地構(gòu)造可取消活動提供更大的靈活性。我們很少希望一個活動立即停止;如果活動在正在進行更新的時候被取消,那么程序數(shù)據(jù)結(jié)構(gòu)可能處于不一致狀態(tài)。中斷允許一個可取消活動來清理正在進行的工作,恢復(fù)不變量,通知其他活動它要被取消,然后才終止。
/* * 這個對象的線程被可中斷的I/O操作阻塞,這個blocker的interrupt方法應(yīng) * 該被設(shè)置完中斷狀態(tài)后觸發(fā) */ private volatile Interruptible blocker; private final Object blockerLock = new Object(); /* 設(shè)置blocker; invoked via sun.misc.SharedSecrets from java.nio code */ void blockedOn(Interruptible b) { synchronized (blockerLock) { blocker = b; } } public void interrupt() { if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) { //如果被可中斷IO阻塞,走此邏輯 Interruptible b = blocker; if (b != null) { interrupt0(); // 僅僅設(shè)置interrupt標(biāo)識位 b.interrupt(this); return; } } interrupt0(); } //當(dāng)前線程是否被中斷,并清空中斷狀態(tài)(連續(xù)兩次調(diào)用,第二次一定返回false) public static boolean interrupted() { return currentThread().isInterrupted(true); } //當(dāng)前線程是否被中,根據(jù)true,false來是否重置中斷zhuangt private native boolean isInterrupted(boolean ClearInterrupted); //當(dāng)前線程是否被中斷,不修改中斷狀態(tài) public boolean isInterrupted() { return isInterrupted(false); }
其它還有很多調(diào)試的方法activeCount,dumpStack就不討論了
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/70045.html
摘要:源碼閱讀創(chuàng)建鎖和同步類中使用的基礎(chǔ)的線程阻塞原語除非你是多線程專家,而且你要自己設(shè)計和實現(xiàn)阻塞式線程同步機制比如等等,否則你不需要用和。 LockSupport源碼閱讀 /* * 創(chuàng)建鎖和同步類中使用的基礎(chǔ)的線程阻塞原語 * * 除非你是多線程專家,而且你要自己設(shè)計和實現(xiàn)阻塞式線程同步機制(比如lock、condition等等),否則你不需要用park和unpark。這兩個原語是...
摘要:前言上次的博客中我們著重介紹了的機制,這次我們將聚焦到自定義擴展上來。在很多情形下我們需要在測試過程中加入一些自定義的動作,這些就需要對進行包裝,為此提供了以接口和為基礎(chǔ)的擴展機制。 前言 上次的博客中我們著重介紹了Junit的Validator機制,這次我們將聚焦到自定義擴展Rule上來。在很多情形下我們需要在測試過程中加入一些自定義的動作,這些就需要對statement進行包裝,...
摘要:在深入理解中的變量上中我們看到的引入,使得可以很方便地在多線程環(huán)境中使用局部變量。特別需要注意的是,基類的并不會屏蔽派生類中的創(chuàng)建。到此,整個源碼核心部分已經(jīng)理解的差不多了,只剩下用來執(zhí)行清除工作。 在 深入理解Python中的ThreadLocal變量(上) 中我們看到 ThreadLocal 的引入,使得可以很方便地在多線程環(huán)境中使用局部變量。如此美妙的功能到底是怎樣實現(xiàn)的?如果你...
閱讀 3427·2021-11-25 09:43
閱讀 3473·2021-11-19 09:40
閱讀 2481·2021-10-14 09:48
閱讀 1297·2021-09-09 11:39
閱讀 1936·2019-08-30 15:54
閱讀 2834·2019-08-30 15:44
閱讀 2007·2019-08-29 13:12
閱讀 1552·2019-08-29 12:59