【高併發】朋友去面試竟然栽在了Thread類的源碼上

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"大家好,我是冰河~~","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最近和一個朋友聊天,他跟我說起了他去XXX公司面試的情況,面試官的一個問題把他打懵了!竟然問他:你經常使用Thread創建線程,那你看過Thread類的源碼嗎?我這個朋友自然是沒看過Thread類的源碼,然後,就沒有然後了!!!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以,我們學習技術不僅需要知其然,更需要知其所以然,今天,我們就一起來簡單看看Thread類的源碼。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"注意:本文是基於JDK 1.8來進行分析的。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Thread類的繼承關係","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以使用下圖來表示Thread類的繼承關係。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/df/df4fb4aca69944039b1fd0a74b6a6abb.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由上圖我們可以看出,Thread類實現了Runnable接口,而Runnable在JDK 1.8中被@FunctionalInterface註解標記爲函數式接口,Runnable接口在JDK 1.8中的源代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@FunctionalInterface\npublic interface Runnable {\n public abstract void run();\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Runnable接口的源碼比較簡單,只是提供了一個run()方法,這裏就不再贅述了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,我們再來看看@FunctionalInterface註解的源碼,如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface FunctionalInterface {}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到,@FunctionalInterface註解聲明標記在Java類上,並在程序運行時生效。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Thread類的源碼剖析","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Thread類定義","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Thread在java.lang包下,Thread類的定義如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class Thread implements Runnable {\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"加載本地資源","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"打開Thread類後,首先,我們會看到在Thread類的最開始部分,定義了一個靜態本地方法registerNatives(),這個方法主要用來註冊一些本地系統的資源。並在靜態代碼塊中調用這個本地方法,如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//定義registerNatives()本地方法註冊系統資源\nprivate static native void registerNatives();\nstatic {\n //在靜態代碼塊中調用註冊本地系統資源的方法\n registerNatives();\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Thread中的成員變量","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Thread類中的成員變量如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//當前線程的名稱\nprivate volatile String name;\n//線程的優先級\nprivate int priority;\nprivate Thread threadQ;\nprivate long eetop;\n//當前線程是否是單步線程\nprivate boolean single_step;\n//當前線程是否在後臺運行\nprivate boolean daemon = false;\n//Java虛擬機的狀態\nprivate boolean stillborn = false;\n//真正在線程中執行的任務\nprivate Runnable target;\n//當前線程所在的線程組\nprivate ThreadGroup group;\n//當前線程的類加載器\nprivate ClassLoader contextClassLoader;\n//訪問控制上下文\nprivate AccessControlContext inheritedAccessControlContext;\n//爲匿名線程生成名稱的編號\nprivate static int threadInitNumber;\n//與此線程相關的ThreadLocal,這個Map維護的是ThreadLocal類\nThreadLocal.ThreadLocalMap threadLocals = null;\n//與此線程相關的ThreadLocal\nThreadLocal.ThreadLocalMap inheritableThreadLocals = null;\n//當前線程請求的堆棧大小,如果未指定堆棧大小,則會交給JVM來處理\nprivate long stackSize;\n//線程終止後存在的JVM私有狀態\nprivate long nativeParkEventPointer;\n//線程的id\nprivate long tid;\n//用於生成線程id\nprivate static long threadSeqNumber;\n//當前線程的狀態,初始化爲0,代表當前線程還未啓動\nprivate volatile int threadStatus = 0;\n//由(私有)java.util.concurrent.locks.LockSupport.setBlocker設置\n//使用java.util.concurrent.locks.LockSupport.getBlocker訪問\nvolatile Object parkBlocker;\n//Interruptible接口中定義了interrupt方法,用來中斷指定的線程\nprivate volatile Interruptible blocker;\n//當前線程的內部鎖\nprivate final Object blockerLock = new Object();\n//線程擁有的最小優先級\npublic final static int MIN_PRIORITY = 1;\n//線程擁有的默認優先級\npublic final static int NORM_PRIORITY = 5;\n//線程擁有的最大優先級\npublic final static int MAX_PRIORITY = 10;\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從Thread類的成員變量,我們可以看出,Thread類本質上不是一個任務,它是一個實實在在的線程對象,在Thread類中擁有一個Runnable類型的成員變量target,而這個target成員變量就是需要在Thread線程對象中執行的任務。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"線程的狀態定義","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在Thread類的內部,定義了一個枚舉State,如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public enum State {\n //初始化狀態\n NEW,\n //可運行狀態,此時的可運行包括運行中的狀態和就緒狀態\n RUNNABLE,\n //線程阻塞狀態\n BLOCKED,\n //等待狀態\n WAITING,\n //超時等待狀態\n TIMED_WAITING,\n //線程終止狀態\n TERMINATED;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個枚舉類中的狀態就代表了線程生命週期的各狀態。我們可以使用下圖來表示線程各個狀態之間的轉化關係。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/18/18a7187119ae64456205521106a3e194.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"NEW:初始狀態,線程被構建,但是還沒有調用start()方法。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"RUNNABLE:可運行狀態,可運行狀態可以包括:運行中狀態和就緒狀態。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"BLOCKED:阻塞狀態,處於這個狀態的線程需要等待其他線程釋放鎖或者等待進入synchronized。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WAITING:表示等待狀態,處於該狀態的線程需要等待其他線程對其進行通知或中斷等操作,進而進入下一個狀態。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"TIME_WAITING:超時等待狀態。可以在一定的時間自行返回。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"TERMINATED:終止狀態,當前線程執行完畢。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Thread類的構造方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Thread類中的所有構造方法如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public Thread() {\n init(null, null, \"Thread-\" + nextThreadNum(), 0);\n}\npublic Thread(Runnable target) {\n init(null, target, \"Thread-\" + nextThreadNum(), 0);\n}\nThread(Runnable target, AccessControlContext acc) {\n init(null, target, \"Thread-\" + nextThreadNum(), 0, acc, false);\n}\npublic Thread(ThreadGroup group, Runnable target) {\n init(group, target, \"Thread-\" + nextThreadNum(), 0);\n}\npublic Thread(String name) {\n init(null, null, name, 0);\n}\npublic Thread(ThreadGroup group, String name) {\n init(group, null, name, 0);\n}\npublic Thread(Runnable target, String name) {\n init(null, target, name, 0);\n}\npublic Thread(ThreadGroup group, Runnable target, String name) {\n init(group, target, name, 0);\n}\npublic Thread(ThreadGroup group, Runnable target, String name,\n long stackSize) {\n init(group, target, name, stackSize);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中,我們最經常使用的就是如下幾個構造方法了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public Thread() {\n init(null, null, \"Thread-\" + nextThreadNum(), 0);\n}\npublic Thread(Runnable target) {\n init(null, target, \"Thread-\" + nextThreadNum(), 0);\n}\npublic Thread(String name) {\n init(null, null, name, 0);\n}\npublic Thread(ThreadGroup group, String name) {\n init(group, null, name, 0);\n}\npublic Thread(Runnable target, String name) {\n init(null, target, name, 0);\n}\npublic Thread(ThreadGroup group, Runnable target, String name) {\n init(group, target, name, 0);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過Thread類的源碼,我們可以看出,Thread類在進行初始化的時候,都是調用的init()方法,接下來,我們看看init()方法是個啥。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"init()方法","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private void init(ThreadGroup g, Runnable target, String name, long stackSize) {\n init(g, target, name, stackSize, null, true);\n}\nprivate void init(ThreadGroup g, Runnable target, String name,\n long stackSize, AccessControlContext acc,\n boolean inheritThreadLocals) {\n //線程的名稱爲空,拋出空指針異常\n if (name == null) {\n throw new NullPointerException(\"name cannot be null\");\n }\n\n this.name = name;\n Thread parent = currentThread();\n //獲取系統安全管理器\n SecurityManager security = System.getSecurityManager();\n //線程組爲空\n if (g == null) {\n //獲取的系統安全管理器不爲空\n if (security != null) {\n //從系統安全管理器中獲取一個線程分組\n g = security.getThreadGroup();\n }\n //線程分組爲空,則從父線程獲取\n if (g == null) {\n g = parent.getThreadGroup();\n }\n }\n //檢查線程組的訪問權限\n g.checkAccess();\n //檢查權限\n if (security != null) {\n if (isCCLOverridden(getClass())) {\n security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);\n }\n }\n g.addUnstarted();\n //當前線程繼承父線程的相關屬性\n this.group = g;\n this.daemon = parent.isDaemon();\n this.priority = parent.getPriority();\n if (security == null || isCCLOverridden(parent.getClass()))\n this.contextClassLoader = parent.getContextClassLoader();\n else\n this.contextClassLoader = parent.contextClassLoader;\n this.inheritedAccessControlContext =\n acc != null ? acc : AccessController.getContext();\n this.target = target;\n setPriority(priority);\n if (inheritThreadLocals && parent.inheritableThreadLocals != null)\n this.inheritableThreadLocals =\n ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);\n /* Stash the specified stack size in case the VM cares */\n this.stackSize = stackSize;\n\n //設置線程id\n tid = nextThreadID();\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Thread類中的構造方法是被創建Thread線程的線程調用的,此時,調用Thread的構造方法創建線程的線程就是父線程,在init()方法中,新創建的Thread線程會繼承父線程的部分屬性。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"run()方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"既然Thread類實現了Runnable接口,則Thread類就需要實現Runnable接口的run()方法,如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Override\npublic void run() {\n if (target != null) {\n target.run();\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到,Thread類中的run()方法實現非常簡單,只是調用了Runnable對象的run()方法。所以,真正的任務是運行在run()方法中的。另外,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"需要注意的是:直接調用Runnable接口的run()方法不會創建新線程來執行任務,如果需要創建新線程執行任務,則需要調用Thread類的start()方法。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"start()方法","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public synchronized void start() {\n //線程不是初始化狀態,則直接拋出異常\n if (threadStatus != 0)\n throw new IllegalThreadStateException();\n //添加當前啓動的線程到線程組\n group.add(this);\n //標記線程是否已經啓動\n boolean started = false;\n try {\n //調用本地方法啓動線程\n start0();\n //將線程是否啓動標記爲true\n started = true;\n } finally {\n try {\n //線程未啓動成功\n if (!started) {\n //將線程在線程組裏標記爲啓動失敗\n group.threadStartFailed(this);\n }\n } catch (Throwable ignore) {\n /* do nothing. If start0 threw a Throwable then\n it will be passed up the call stack */\n }\n }\n}\n\nprivate native void start0();\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從start()方法的源代碼,我們可以看出:","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"start()方法使用synchronized關鍵字修飾,說明start()方法是同步的,它會在啓動線程前檢查線程的狀態,如果不是初始化狀態,則直接拋出異常。所以,一個線程只能啓動一次,多次啓動是會拋出異常的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"也是面試的一個坑:面試官:【問題一】能不能多次調用Thread類的start()方法來啓動線程嗎?【問題二】多次調用Thread線程的start()方法會發生什麼?【問題三】爲什麼會拋出異常?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"調用start()方法後,新創建的線程就會處於就緒狀態(如果沒有分配到CPU執行),當有空閒的CPU時,這個線程就會被分配CPU來執行,此時線程的狀態爲運行狀態,JVM會調用線程的run()方法執行任務。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"sleep()方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"sleep()方法可以使當前線程休眠,其代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//本地方法,真正讓線程休眠的方法\npublic static native void sleep(long millis) throws InterruptedException;\n\npublic static void sleep(long millis, int nanos)\n throws InterruptedException {\n if (millis < 0) {\n throw new IllegalArgumentException(\"timeout value is negative\");\n }\n\n if (nanos < 0 || nanos > 999999) {\n throw new IllegalArgumentException(\n \"nanosecond timeout value out of range\");\n }\n\n if (nanos >= 500000 || (nanos != 0 && millis == 0)) {\n millis++;\n }\n //調用本地方法\n sleep(millis);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"sleep()方法會讓當前線程休眠一定的時間,這個時間通常是毫秒值,這裏需要注意的是:","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"調用sleep()方法使線程休眠後,線程不會釋放相應的鎖。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"join()方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"join()方法會一直等待線程超時或者終止,代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public final synchronized void join(long millis)\n throws InterruptedException {\n long base = System.currentTimeMillis();\n long now = 0;\n\n if (millis < 0) {\n throw new IllegalArgumentException(\"timeout value is negative\");\n }\n\n if (millis == 0) {\n while (isAlive()) {\n wait(0);\n }\n } else {\n while (isAlive()) {\n long delay = millis - now;\n if (delay <= 0) {\n break;\n }\n wait(delay);\n now = System.currentTimeMillis() - base;\n }\n }\n}\n\npublic final synchronized void join(long millis, int nanos)\n throws InterruptedException {\n\n if (millis < 0) {\n throw new IllegalArgumentException(\"timeout value is negative\");\n }\n\n if (nanos < 0 || nanos > 999999) {\n throw new IllegalArgumentException(\n \"nanosecond timeout value out of range\");\n }\n\n if (nanos >= 500000 || (nanos != 0 && millis == 0)) {\n millis++;\n }\n\n join(millis);\n}\n\npublic final void join() throws InterruptedException {\n join(0);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"join()方法的使用場景往往是啓動線程執行任務的線程,調用執行線程的join()方法,等待執行線程執行任務,直到超時或者執行線程終止。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"interrupt()方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"interrupt()方法是中斷當前線程的方法,它通過設置線程的中斷標誌位來中斷當前線程。此時,如果爲線程設置了中斷標誌位,可能會拋出InteruptedExeption異常,同時,會清除當前線程的中斷狀態。這種方式中斷線程比較安全,它能使正在執行的任務執行能夠繼續執行完畢,而不像stop()方法那樣強制線程關閉。代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public void interrupt() {\n if (this != Thread.currentThread())\n checkAccess();\n\n synchronized (blockerLock) {\n Interruptible b = blocker;\n if (b != null) {\n interrupt0(); // Just to set the interrupt flag\n b.interrupt(this);\n return;\n }\n }\n //調用本地方法中斷線程\n interrupt0();\n}\nprivate native void interrupt0();\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作爲技術人員,要知其然,更要知其所以然,我那個朋友技術本身不錯,各種框架拿來就用,基本沒看過常用的框架源碼和JDK中常用的API,屬於那種CRUD型程序員,這次面試就栽在了一個簡單的Thread類上,所以,大家在學會使用的時候,一定要了解下底層的實現纔好啊!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"好了,今天就到這兒吧,我是冰河,我們下期見~~","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章