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