(給ImportNew加星標,提高Java技能)
作者:行者路上
連結:blog.csdn.net/u012998254/article/details/79400549
1、執行緒與行程
- 行程是一個物體。每一個行程都有它自己的地址空間,一般情況下,包括文字區域(text region)、資料區域(data region)和堆疊(stack region)。文字區域儲存處理器執行的程式碼;資料區域儲存變數和行程執行期間使用的動態分配的記憶體;堆疊區域儲存著活動過程呼叫的指令和本地變數。
- 一個標準的執行緒由執行緒ID,當前指令指標(PC),暫存器集合和堆疊組成。另外,執行緒是行程中的一個物體,是被系統獨立排程和分派的基本單位,執行緒自己不擁有系統資源,只擁有一點兒在執行中必不可少的資源,但它可與同屬一個行程的其它執行緒共享行程所擁有的全部資源。
- 區別不同
- 地址空間:行程內的一個執行單元;行程至少有一個執行緒;它們共享行程的地址空間;而行程有自己獨立的地址空間;
- 資源擁有:行程是資源分配和擁有的單位,同一個行程內的執行緒共享行程的資
- 執行緒是處理器排程的基本單位,但行程不是.
- 二者均可併發執行.
2、 守護執行緒
在Java中有兩類執行緒:使用者執行緒 (User Thread)、守護執行緒 (Daemon Thread)。
守護執行緒和使用者執行緒的區別在於:守護執行緒依賴於建立它的執行緒,而使用者執行緒則不依賴。舉個簡單的例子:如果在main執行緒中建立了一個守護執行緒,當main方法執行完畢之後,守護執行緒也會隨著消亡。而使用者執行緒則不會,使用者執行緒會一直執行直到其執行完畢。在JVM中,像垃圾收集器執行緒就是守護執行緒。
3、java thread狀態
- NEW 狀態是指執行緒剛建立, 尚未啟動
- RUNNABLE 狀態是執行緒正在正常執行中, 當然可能會有某種耗時計算/IO等待的操作/CPU時間片切換等, 這個狀態下發生的等待一般是其他系統資源, 而不是鎖, Sleep等
- BLOCKED 這個狀態下, 是在多個執行緒有同步操作的場景, 比如正在等待另一個執行緒的synchronized 塊的執行釋放, 也就是這裡是執行緒在等待進入臨界區
- WAITING 這個狀態下是指執行緒擁有了某個鎖之後, 呼叫了他的wait方法, 等待其他執行緒/鎖擁有者呼叫 notify / notifyAll 一遍該執行緒可以繼續下一步操作, 這裡要區分 BLOCKED 和 WATING 的區別, 一個是在臨界點外面等待進入, 一個是在理解點裡面wait等待別人notify, 執行緒呼叫了join方法 join了另外的執行緒的時候, 也會進入WAITING狀態, 等待被他join的執行緒執行結束
- TIMED_WAITING 這個狀態就是有限的(時間限制)的WAITING, 一般出現在呼叫wait(long), join(long)等情況下, 另外一個執行緒sleep後, 也會進入TIMED_WAITING狀態
- TERMINATED 這個狀態下表示 該執行緒的run方法已經執行完畢了, 基本上就等於死亡了(當時如果執行緒被持久持有, 可能不會被回收)
4、請說出與執行緒同步以及執行緒排程相關的方法。
- wait():使一個執行緒處於等待(阻塞)狀態,並且釋放所持有的物件的鎖;
- sleep():使一個正在執行的執行緒處於睡眠狀態,是一個靜態方法,呼叫此方法要處理InterruptedException異常;
- notify():喚醒一個處於等待狀態的執行緒,當然在呼叫此方法的時候,並不能確切的喚醒某一個等待狀態的執行緒,而是由JVM確定喚醒哪個執行緒,而且與優先順序無關;
- notityAll():喚醒所有處於等待狀態的執行緒,該方法並不是將物件的鎖給所有執行緒,而是讓它們競爭,只有獲得鎖的執行緒才能進入就緒狀態;
5、行程排程演演算法
實時系統:FIFO(First Input First Output,先進先出演演算法),SJF(Shortest Job First,最短作業優先演演算法),SRTF(Shortest Remaining Time First,最短剩餘時間優先演演算法)。
互動式系統:RR(Round Robin,時間片輪轉演演算法),HPF(Highest Priority First,最高優先順序演演算法),多級佇列,最短行程優先,保證排程,彩票排程,公平分享排程。
6、wait()和sleep()的區別
- sleep來自Thread類,和wait來自Object類
- 呼叫sleep()方法的過程中,執行緒不會釋放物件鎖。而 呼叫 wait 方法執行緒會釋放物件鎖
- sleep睡眠後不出讓系統資源,wait讓出系統資源其他執行緒可以佔用CPU
- sleep(milliseconds)需要指定一個睡眠時間,時間一到會自動喚醒
7、ThreadLocal,以及死鎖分析
hreadLocal為每個執行緒維護一個本地變數。
採用空間換時間,它用於執行緒間的資料隔離,為每一個使用該變數的執行緒提供一個副本,每個執行緒都可以獨立地改變自己的副本,而不會和其他執行緒的副本衝突。
ThreadLocal類中維護一個Map,用於儲存每一個執行緒的變數副本,Map中元素的鍵為執行緒物件,而值為對應執行緒的變數副本。
8、Synchronized 與Lock
- ReentrantLock 擁有Synchronized相同的併發性和記憶體語意,此外還多了 鎖投票,定時鎖等候和中斷鎖等候 ,執行緒A和B都要獲取物件O的鎖定,假設A獲取了物件O鎖,B將等待A釋放對O的鎖定, 如果使用 synchronized ,如果A不釋放,B將一直等下去,不能被中斷 ,如果 使用ReentrantLock,如果A不釋放,可以使B在等待了足夠長的時間以後,中斷等待,而乾別的事情
- ReentrantLock獲取鎖定與三種方式:
- lock(), 如果獲取了鎖立即傳回,如果別的執行緒持有鎖,當前執行緒則一直處於休眠狀態,直到獲取鎖
- tryLock(), 如果獲取了鎖立即傳回true,如果別的執行緒正持有鎖,立即傳回false;
- tryLock(long timeout,TimeUnit unit), 如果獲取了鎖定立即傳回true,如果別的執行緒正持有鎖,會等待引數給定的時間,在等待的過程中,如果獲取了鎖定,就傳回true,如果等待超時,傳回false;
- lockInterruptibly:如果獲取了鎖定立即傳回,如果沒有獲取鎖定,當前執行緒處於休眠狀態,直到或者鎖定,或者當前執行緒被別的執行緒中斷
總體的結論先擺出來:
synchronized:
在資源競爭不是很激烈的情況下,偶爾會有同步的情形下,synchronized是很合適的。原因在於,編譯程式通常會盡可能的進行最佳化synchronized,另外可讀性非常好,不管用沒用過5.0多執行緒包的程式員都能理解。
ReentrantLock:
ReentrantLock提供了多樣化的同步,比如有時間限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在資源競爭不激烈的情形下,效能稍微比synchronized差點點。但是當同步非常激烈的時候,synchronized的效能一下子能下降好幾十倍。而ReentrantLock確還能維持常態。
9、Volatile和Synchronized
Volatile和Synchronized四個不同點:
- 粒度不同,前者針對變數 ,後者鎖物件和類
- syn阻塞,volatile執行緒不阻塞
- syn保證三大特性,volatile不保證原子性
- syn編譯器最佳化,volatile不最佳化
要使 volatile 變數提供理想的執行緒安全,必須同時滿足下麵兩個條件:
- 對變數的寫操作不依賴於當前值。
- 該變數沒有包含在具有其他變數的不變式中。
10、CAS
CAS是樂觀鎖技術,當多個執行緒嘗試使用CAS同時更新同一個變數時,只有其中一個執行緒能更新變數的值,而其它執行緒都失敗,失敗的執行緒並不會被掛起,而是被告知這次競爭中失敗,並可以再次嘗試。CAS有3個運算元,記憶體值V,舊的預期值A,要修改的新值B。當且僅當預期值A和記憶體值V相同時,將記憶體值V修改為B,否則什麼都不做。
11、Java中Unsafe類詳解
- 透過Unsafe類可以分配記憶體,可以釋放記憶體;類中提供的3個本地方法allocateMemory、reallocateMemory、freeMemory分別用於分配記憶體,擴充記憶體和釋放記憶體,與C語言中的3個方法對應。
- 可以定位物件某欄位的記憶體位置,也可以修改物件的欄位值,即使它是私有的;
- 掛起與恢復:將一個執行緒進行掛起是透過park方法實現的,呼叫 park後,執行緒將一直阻塞直到超時或者中斷等條件出現。unpark可以終止一個掛起的執行緒,使其恢復正常。整個併發框架中對執行緒的掛起操作被封裝在 LockSupport類中,LockSupport類中有各種版本pack方法,但最終都呼叫了Unsafe.park()方法。
- cas
12、執行緒池
執行緒池的作用:
在程式啟動的時候就建立若干執行緒來響應處理,它們被稱為執行緒池,裡面的執行緒叫工作執行緒
第一:降低資源消耗。透過重覆利用已建立的執行緒降低執行緒建立和銷毀造成的消耗。
第二:提高響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行。
第三:提高執行緒的可管理性。
常用執行緒池:ExecutorService 是主要的實現類,其中常用的有
Executors.newSingleT
hreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。
13、ThreadPoolExecutor
構造方法引數說明
corePoolSize:核心執行緒數,預設情況下核心執行緒會一直存活,即使處於閑置狀態也不會受存keepAliveTime限制。除非將allowCoreThreadTimeOut設定為true。
maximumPoolSize:執行緒池所能容納的最大執行緒數。超過這個數的執行緒將被阻塞。當任務佇列為沒有設定大小的LinkedBlockingDeque時,這個值無效。
keepAliveTime:非核心執行緒的閑置超時時間,超過這個時間就會被回收。
unit:指定keepAliveTime的單位,如TimeUnit.SECONDS。當將allowCoreThreadTimeOut設定為true時對corePoolSize生效。
workQueue:執行緒池中的任務佇列.
常用的有三種佇列,SynchronousQueue,LinkedBlockingDeque,ArrayBlockingQueue。
threadFactory:執行緒工廠,提供建立新執行緒的功能。ThreadFactory是一個介面,只有一個方法
原理
- 如果當前池大小 poolSize 小於 corePoolSize ,則建立新執行緒執行任務。
- 如果當前池大小 poolSize 大於 corePoolSize ,且等待佇列未滿,則進入等待佇列
- 如果當前池大小 poolSize 大於 corePoolSize 且小於 maximumPoolSize ,且等待佇列已滿,則建立新執行緒執行任務。
- 如果當前池大小 poolSize 大於 corePoolSize 且大於 maximumPoolSize ,且等待佇列已滿,則呼叫拒絕策略來處理該任務。
- 執行緒池裡的每個執行緒執行完任務後不會立刻退出,而是會去檢查下等待佇列裡是否還有執行緒任務需要執行,如果在 keepAliveTime 裡等不到新的任務了,那麼執行緒就會退出。
13、Executor拒絕策略
- AbortPolicy:為java執行緒池預設的阻塞策略,不執行此任務,而且直接丟擲一個執行時異常,切記ThreadPoolExecutor.execute需要try
catch,否則程式會直接退出.
- DiscardPolicy:直接拋棄,任務不執行,空方法
- DiscardOldestPolicy:從佇列裡面拋棄head的一個任務,並再次execute 此task。
- CallerRunsPolicy:在呼叫execute的執行緒裡面執行此command,會阻塞入
- 使用者自定義拒絕策略:實現RejectedExecutionHandler,並自己定義策略樣式
14、CachedThreadPool 、 FixedThreadPool、SingleThreadPool
- newSingleThreadExecutor :建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務, 保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行
適用場景:任務少 ,並且不需要併發執行
- newCachedThreadPool :建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閑執行緒,若無可回收,則新建執行緒.
執行緒沒有任務要執行時,便處於空閑狀態,處於空閑狀態的執行緒並不會被立即銷毀(會被快取住),只有當空閑時間超出一段時間(預設為60s)後,執行緒池才會銷毀該執行緒(相當於清除過時的快取)。新任務到達後,執行緒池首先會讓被快取住的執行緒(空閑狀態)去執行任務,如果沒有可用執行緒(無空閑執行緒),便會建立新的執行緒。
適用場景:處理任務速度 > 提交任務速度,耗時少的任務(避免無限新增執行緒)
- newFixedThreadPool :建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。
- newScheduledThreadPool:建立一個定長執行緒池,支援定時及週期性任務執行
15、CopyOnWriteArrayList
CopyOnWriteArrayList : 寫時加鎖,當新增一個元素的時候,將原來的容器進行copy,複製出一個新的容器,然後在新的容器裡面寫,寫完之後再將原容器的取用指向新的容器,而讀的時候是讀舊容器的資料,所以可以進行併發的讀,但這是一種弱一致性的策略。
使用場景:CopyOnWriteArrayList適合使用在讀操作遠遠大於寫操作的場景裡,比如快取。
16、AQS
AQS使用一個int成員變數來表示同步狀態,透過內建的FIFO佇列來完成獲取資源執行緒的排隊工作。
private volatile int state;//共享變數,使用volatile修飾保證執行緒可見性
- 2種同步方式:獨佔式,共享式。獨佔式如ReentrantLock,共享式如Semaphore,CountDownLatch,組合式的如ReentrantReadWriteLock
- 節點的狀態
CANCELLED,值為1,表示當前的執行緒被取消;
SIGNAL,值為-1,表示當前節點的後繼節點包含的執行緒需要執行,也就是unpark;
CONDITION,值為-2,表示當前節點在等待condition,也就是在condition佇列中;
PROPAGATE,值為-3,表示當前場景下後續的acquireShared能夠得以執行;
值為0,表示當前節點在sync佇列中,等待著獲取鎖。
- 模板方法樣式
protected boolean tryAcquire(int arg) : 獨佔式獲取同步狀態,試著獲取,成功傳回true,反之為false
protected boolean tryRelease(int arg) :獨佔式釋放同步狀態,等待中的其他執行緒此時將有機會獲取到同步狀態;
protected int tryAcquireShared(int arg) :共享式獲取同步狀態,傳回值大於等於0,代表獲取成功;反之獲取失敗;
protected boolean tryReleaseShared(int arg) :共享式釋放同步狀態,成功為true,失敗為false
AQS維護一個共享資源state,透過內建的FIFO來完成獲取資源執行緒的排隊工作。該佇列由一個一個的Node結點組成,每個Node結點維護一個prev取用和next取用,分別指向自己的前驅和後繼結點。雙端雙向連結串列。
1.獨佔式:樂觀的併發策略
acquire
a.首先tryAcquire獲取同步狀態,成功則直接傳回;否則,進入下一環節;
b.執行緒獲取同步狀態失敗,就構造一個結點,加入同步佇列中,這個過程要保證執行緒安全;
c.加入佇列中的結點執行緒進入自旋狀態,若是老二結點(即前驅結點為頭結點),才有機會嘗試去獲取同步狀態;否則,當其前驅結點的狀態為SIGNAL,執行緒便可安心休息,進入阻塞狀態,直到被中斷或者被前驅結點喚醒。
release
release的同步狀態相對簡單,需要找到頭結點的後繼結點進行喚醒,若後繼結點為空或處於CANCEL狀態,從後向前遍歷找尋一個正常的結點,喚醒其對應執行緒。
- 共享式:
共享式地獲取同步狀態.同步狀態的方法tryAcquireShared傳回值為int。
a.當傳回值大於0時,表示獲取同步狀態成功,同時還有剩餘同步狀態可供其他執行緒獲取;
b.當傳回值等於0時,表示獲取同步狀態成功,但沒有可用同步狀態了;
c.當傳回值小於0時,表示獲取同步狀態失敗。
- AQS實現公平鎖和非公平鎖
非公平鎖中,那些嘗試獲取鎖且尚未進入等待佇列的執行緒會和等待佇列head結點的執行緒發生競爭。公平鎖中,在獲取鎖時,增加了isFirst(current)判斷,當且僅當,等待佇列為空或當前執行緒是等待佇列的頭結點時,才可嘗試獲取鎖。
16、Java裡的阻塞佇列
7個阻塞佇列。分別是
- ArrayBlockingQueue :一個由陣列結構組成的有界阻塞佇列。
- LinkedBlockingQueue :一個由連結串列結構組成的有界阻塞佇列。
- PriorityBlockingQueue :一個支援優先順序排序的無界阻塞佇列。
- DelayQueue:一個使用優先順序佇列實現的無界阻塞佇列。
- SynchronousQueue:一個不儲存元素的阻塞佇列。
- LinkedTransferQueue:一個由連結串列結構組成的無界阻塞佇列。
- LinkedBlockingDeque:一個由連結串列結構組成的雙向阻塞佇列。
新增元素
Java中的阻塞佇列介面BlockingQueue繼承自Queue介面。BlockingQueue介面提供了3個新增元素方法。
- add:新增元素到佇列裡,新增成功傳回true,由於容量滿了新增失敗會丟擲IllegalStateException異常
- offer:新增元素到佇列裡,新增成功傳回true,新增失敗傳回false
- put:新增元素到佇列裡,如果容量滿了會阻塞直到容量不滿
刪除方法
3個刪除方法
- poll:刪除佇列頭部元素,如果佇列為空,傳回null。否則傳回元素。
- remove:基於物件找到對應的元素,並刪除。刪除成功傳回true,否則傳回false
- take:刪除佇列頭部元素,如果佇列為空,一直阻塞到佇列有元素並刪除
17、condition
對Condition的原始碼理解,主要就是理解等待佇列,等待佇列可以類比同步佇列,而且等待佇列比同步佇列要簡單,因為等待佇列是單向佇列,同步佇列是雙向佇列。
18、DelayQueue
佇列中每個元素都有個過期時間,並且佇列是個優先順序佇列,當從佇列獲取元素時候,只有過期元素才會出佇列。
19、Fork/Join框架
Fork/Join框架是Java 7提供的一個用於並行執行任務的框架,是一個把大任務分割成若干個小任務,最終彙總每個小任務結果後得到大任務結果的框架。Fork/Join框架要完成兩件事情:
- 任務分割:首先Fork/Join框架需要把大的任務分割成足夠小的子任務,如果子任務比較大的話還要對子任務進行繼續分割
- 執行任務併合並結果:分割的子任務分別放到雙端佇列裡,然後幾個啟動執行緒分別從雙端佇列裡獲取任務執行。子任務執行完的結果都放在另外一個佇列裡,啟動一個執行緒從佇列裡取資料,然後合併這些資料。
在Java的Fork/Join框架中,使用兩個類完成上述操作
- ForkJoinTask:我們要使用Fork/Join框架,首先需要建立一個ForkJoin任務。該類提供了在任務中執行fork和join的機制。通常情況下我們不需要直接整合ForkJoinTask類,只需要繼承它的子類,Fork/Join框架提供了兩個子類:
a.RecursiveAction:用於沒有傳回結果的任務
b.RecursiveTask:用於有傳回結果的任務
- ForkJoinPool:ForkJoinTask需要透過ForkJoinPool來執行
任務分割出的子任務會新增到當前工作執行緒所維護的雙端佇列中,進入佇列的頭部。當一個工作執行緒的佇列裡暫時沒有任務時,它會隨機從其他工作執行緒的佇列的尾部獲取一個任務(工作竊取演演算法)。
Fork/Join框架的實現原理
ForkJoinPool由ForkJoinTask陣列和ForkJoinWorkerThread陣列組成,ForkJoinTask陣列負責將存放程式提交給ForkJoinPool,而ForkJoinWorkerThread負責執行這
20、原子操作類
在java.util.concurrent.atomic包下,可以分為四種型別的原子更新類:原子更新基本型別、原子更新陣列型別、原子更新取用和原子更新屬性。
- 原子更新基本型別
使用原子方式更新基本型別,共包括3個類:
AtomicBoolean:原子更新布林變數
AtomicInteger:原子更新整型變數
AtomicLong:原子更新長整型變數
- 原子更新陣列
透過原子更新陣列裡的某個元素,共有3個類:
AtomicIntegerArray:原子更新整型陣列的某個元素
AtomicLongArray:原子更新長整型陣列的某個元素
AtomicReferenceArray:原子更新取用型別陣列的某個元素
AtomicIntegerArray常用的方法有:
int addAndSet(int i, int delta):以原子方式將輸入值與陣列中索引為i的元素相加
boolean compareAndSet(int i, int expect, int update):如果當前值等於預期值,則以原子方式更新陣列中索引為i的值為update值
- 原子更新取用型別
AtomicReference:原子更新取用型別
AtomicReferenceFieldUpdater:原子更新取用型別裡的欄位
AtomicMarkableReference:原子更新帶有標記位的取用型別。
- 原子更新欄位類
如果需要原子更新某個類的某個欄位,就需要用到原子更新欄位類,可以使用以下幾個類:
AtomicIntegerFieldUpdater:原子更新整型欄位
AtomicLongFieldUpdater:原子更新長整型欄位
AtomicStampedReference:原子更新帶有版本號的取用型別。
要想原子更新欄位,需要兩個步驟:
每次必須使用newUpdater建立一個更新器,並且需要設定想要更新的類的欄位
更新類的欄位(屬性)必須為public volatile
21、同步屏障CyclicBarrier
CyclicBarrier 的字面意思是可迴圈使用(Cyclic)的屏障(Barrier)。它要做的事情是,讓一組執行緒到達一個屏障(也可以叫同步點)時被阻塞,直到最後一個執行緒到達屏障時,屏障才會開門,所有被屏障攔截的執行緒才會繼續幹活。CyclicBarrier預設的構造方法是CyclicBarrier(int parties),其引數表示屏障攔截的執行緒數量,每個執行緒呼叫await方法告訴CyclicBarrier我已經到達了屏障,然後當前執行緒被阻塞。
CyclicBarrier和CountDownLatch的區別
CountDownLatch的計數器只能使用一次。而CyclicBarrier的計數器可以使用reset() 方法重置。所以CyclicBarrier能處理更為複雜的業務場景,比如如果計算發生錯誤,可以重置計數器,並讓執行緒們重新執行一次。
CyclicBarrier還提供其他有用的方法,比如getNumberWaiting方法可以獲得CyclicBarrier阻塞的執行緒數量。isBroken方法用來知道阻塞的執行緒是否被中斷。比如以下程式碼執行完之後會傳回true。
22、Semaphore
Semaphore(訊號量)是用來控制同時訪問特定資源的執行緒數量,它透過協調各個執行緒,以保證合理的使用公共資源
Semaphore可以用於做流量控制,特別公用資源有限的應用場景,比如資料庫連線。假如有一個需求,要讀取幾萬個檔案的資料,因為都是IO密集型任務,我們可以啟動幾十個執行緒併發的讀取,但是如果讀到記憶體後,還需要儲存到資料庫中,而資料庫的連線數只有10個,這時我們必須控制只有十個執行緒同時獲取資料庫連線儲存資料,否則會報錯無法獲取資料庫連線。這個時候,我們就可以使用Semaphore來做流控.
23、死鎖,以及解決死鎖
死鎖產生的四個必要條件
互斥條件:資源是獨佔的且排他使用,行程互斥使用資源,即任意時刻一個資源只能給一個行程使用,其他行程若申請一個資源,而該資源被另一行程佔有時,則申請者等待直到資源被佔有者釋放。
不可剝奪條件:行程所獲得的資源在未使用完畢之前,不被其他行程強行剝奪,而只能由獲得該資源的行程資源釋放。
請求和保持條件:行程每次申請它所需要的一部分資源,在申請新的資源的同時,繼續佔用已分配到的資源。
迴圈等待條件:在發生死鎖時必然存在一個行程等待佇列{P1,P2,…,Pn},其中P1等待P2佔有的資源,P2等待P3佔有的資源,…,Pn等待P1佔有的資源,形成一個行程等待環路,環路中每一個行程所佔有的資源同時被另一個申請,也就是前一個行程佔有後一個行程所深情地資源。
解決死鎖
- 死鎖預防,就是不讓上面的四個條件同時成立。
- 合理分配資源。
- 使用銀行家演演算法,如果該行程請求的資源作業系統剩餘量可以滿足,那麼就分配。
24、行程間的通訊方式
- 管道( pipe):管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有親緣關係的行程間使用。行程的親緣關係通常是指父子行程關係。
- 有名管道 (named pipe) : 有名管道也是半雙工的通訊方式,但是它允許無親緣關係行程間的通訊。
- 訊號量( semophore ) : 訊號量是一個計數器,可以用來控制多個行程對共享資源的訪問。它常作為一種鎖機制,防止某行程正在訪問共享資源時,其他行程也訪問該資源。因此,主要作為行程間以及同一行程內不同執行緒之間的同步手段。
- 訊息佇列( message queue ) : 訊息佇列是由訊息的連結串列,存放在核心中並由訊息佇列識別符號標識。訊息佇列剋服了訊號傳遞資訊少、管道只能承載無格式位元組流以及緩衝區大小受限等缺點。
- 訊號 ( sinal ) : 訊號是一種比較複雜的通訊方式,用於通知接收行程某個事件已經發生。
- 共享記憶體( shared memory ) :共享記憶體就是對映一段能被其他行程所訪問的記憶體,這段共享記憶體由一個行程建立,但多個行程都可以訪問。共享記憶體是最快的 IPC 方式,它是針對其他行程間通訊方式執行效率低而專門設計的。它往往與其他通訊機制,如訊號量,配合使用,來實現行程間的同步和通訊。
- 套接字( socket ) : 套解口也是一種行程間通訊機制,與其他通訊機制不同的是,它可用於不同機器間的行程通訊。
中斷
interrupt()的作用是中斷本執行緒。
本執行緒中斷自己是被允許的;其它執行緒呼叫本執行緒的interrupt()方法時,會透過checkAccess()檢查許可權。這有可能丟擲SecurityException異常。
如果本執行緒是處於阻塞狀態:呼叫執行緒的wait(), wait(long)或wait(long, int)會讓它進入等待(阻塞)狀態,或者呼叫執行緒的join(), join(long), join(long, int), sleep(long), sleep(long, int)也會讓它進入阻塞狀態。若執行緒在阻塞狀態時,呼叫了它的interrupt()方法,那麼它的“中斷狀態”會被清除並且會收到一個InterruptedException異常。例如,執行緒透過wait()進入阻塞狀態,此時透過interrupt()中斷該執行緒;呼叫interrupt()會立即將執行緒的中斷標記設為“true”,但是由於執行緒處於阻塞狀態,所以該“中斷標記”會立即被清除為“false”,同時,會產生一個InterruptedException的異常。
如果執行緒被阻塞在一個Selector選擇器中,那麼透過interrupt()中斷它時;執行緒的中斷標記會被設定為true,並且它會立即從選擇操作中傳回。
如果不屬於前面所說的情況,那麼透過interrupt()中斷執行緒時,它的中斷標記會被設定為“true”。
中斷一個“已終止的執行緒”不會產生任何操作。
- 終止處於“阻塞狀態”的執行緒
通常,我們透過“中斷”方式終止處於“阻塞狀態”的執行緒。
當執行緒由於被呼叫了sleep(), wait(), join()等方法而進入阻塞狀態;若此時呼叫執行緒的interrupt()將執行緒的中斷標記設為true。由於處於阻塞狀態,中斷標記會被清除,同時產生一個InterruptedException異常。將InterruptedException放在適當的為止就能終止執行緒,
- 終止處於“執行狀態”的執行緒
interrupted() 和 isInterrupted()的區別
最後談談 interrupted() 和 isInterrupted()。
interrupted() 和 isInterrupted()都能夠用於檢測物件的“中斷標記”。
區別是,interrupted()除了傳回中斷標記之外,它還會清除中斷標記(即將中斷標記設為false);而isInterrupted()僅僅傳回中斷標記。
朋友會在“發現-看一看”看到你“在看”的內容