發展簡史 執行緒的引入:
60年代,在OS中能擁有資源和獨立運行的基本單位是進程,然而隨著計算機技術的發展,進程出現了很多弊端,一是由於進程是資源擁有者,創建、撤消與切換存在較大的時空開銷,因此需要引入輕型進程;二是由於對稱多處理機(SMP)出現,可以滿足多個運行單位,而多個進程並行開銷過大。
因此在80年代,出現了能獨立運行的基本單位——執行緒(Threads)。
適用範圍 2.前後台處理
3.異步處理
特點 執行緒的使用 在
多執行緒 OS中,通常是在一個
進程 中包括多個執行緒,每個執行緒都是作為利用CPU的基本單位,是花費最小開銷的實體。執行緒具有以下屬性。
1)輕型實體
執行緒中的實體基本上不擁有
系統資源 ,只是有一點必不可少的、能保證獨立
運行 的資源。
執行緒的實體包括程式、數據和TCB。執行緒是動態概念,它的動態特性由執行緒控制塊TCB(Thread Control Block)描述。TCB包括以下信息:
(1)執行緒狀態。
(2)當執行緒不運行時,被保存的現場資源。
(3)一組執行堆疊。
(4)存放每個執行緒的局部變數主存區。
(5)訪問同一個進程中的主存和其它資源。
2)獨立調度和分派的基本單位。
在多執行緒OS中,執行緒是能獨立
運行 的基本單位,因而也是獨立調度和分派的基本單位。由於執行緒很“輕”,故執行緒的切換非常迅速且開銷小(在同一
進程 中的)。
3)可並發執行。
在一個
進程 中的多個執行緒之間,可以並發執行,甚至允許在一個進程中所有執行緒都能並發執行;同樣,不同進程中的執行緒也能並發執行,充分利用和發揮了
處理機 與外圍設備並行工作的能力。
4)共享 進程 資源。
執行緒 在同一
進程 中的各個執行緒,都可以共享該進程所擁有的資源,這首先表現在:所有執行緒都具有相同的
地址空間 (進程的地址空間),這意味著,執行緒可以訪問該地址空間的每一個虛地址;此外,還可以訪問進程所擁有的已打開
檔案 、定時器、
信號量 機構等。由於同一個
進程 內的執行緒
共享記憶體 和
檔案 ,所以執行緒之間互相通信不必調用
核心 。
與進程比較 執行緒 進程 是資源分配的基本單位。所有與該進程有關的資源,都被記錄在
進程控制塊 PCB中。以表示該進程擁有這些資源或正在使用它們。
另外,進程也是搶占處理機的調度單位,它擁有一個完整的虛擬地址空間。當進程發生調度時,不同的進程擁有不同的虛擬地址空間,而同一進程內的不同執行緒共享同一地址空間。
與進程相對應,執行緒與資源分配無關,它屬於某一個進程,並與進程內的其他執行緒一起共享進程的資源。
通常在一個進程中可以包含若干個執行緒,它們可以利用進程所擁有的資源。在引入執行緒的作業系統中,通常都是把進程作為分配資源的基本單位,而把執行緒作為獨立運行和獨立調度的基本單位。由於執行緒比進程更小,基本上不擁有系統資源,故對它的調度所付出的開銷就會小得多,能更高效的提高系統內多個程式間並發執行的程度,從而顯著提高系統資源的利用率和吞吐量。因而近年來推出的
通用作業系統 都引入了執行緒,以便進一步提高系統的
並發性 ,並把它視為現代作業系統的一個重要指標。
執行緒與進程的區別可以歸納為以下4點:
1)地址空間和其它資源(如打開檔案):進程間相互獨立,同一進程的各執行緒間共享。某進程內的執行緒在其它進程不可見。
2)通信:
進程間通信 IPC ,執行緒間可以直接讀寫進程數據段(如全局變數)來進行通信——需要
進程同步 和互斥手段的輔助,以保證數據的一致性。
3)調度和切換:執行緒上下文切換比進程上下文切換要快得多。
4)在多執行緒OS中,執行緒不是一個可執行的實體。
守護執行緒 守護執行緒 是特殊的執行緒,一般用於在後台為其他執行緒提供服務.
Java中,isDaemon():判斷一個執行緒是否為
守護執行緒 .
Java中,setDaemon():設定一個執行緒為
守護執行緒 .
/*** 本執行緒設定了一個逾時時間* 該執行緒開始運行後,經過指定逾時時間,* 該執行緒會拋出一個未檢查異常通知調用該執行緒的程式逾時* 在逾時結束前可以調用該類的cancel方法取消計時* @author solonote*/public class TimeoutThread extends Thread{/*** 計時器逾時時間*/private long timeout;/*** 計時是否被取消*/private boolean isCanceled = false;/*** 當計時器逾時時拋出的異常*/private TimeoutException timeoutException;/*** 構造器* @param timeout 指定逾時的時間*/public TimeoutThread(long timeout,TimeoutException timeoutErr) {super();this.timeout = timeout;this.timeoutException = timeoutErr;//設定本執行緒為守護執行緒this.setDaemon(true);}/*** 取消計時*/public synchronized void cancel(){isCanceled = true;}/*** 啟動逾時計時器*/public void run(){try {Thread.sleep(timeout);if(!isCanceled)throw timeoutException;} catch (InterruptedException e) {e.printStackTrace();}}}
執行緒的同步 執行緒的同步是Java
多執行緒 編程的難點,往往開發者搞不清楚什麼是
競爭資源 、什麼時候需要考慮同步,怎么同步等等問題,當然,這些問題沒有很明確的答案,但有些原則問題需要考慮,是否有
競爭資源 被同時改動的問題?對於同步,在具體的Java代碼中需要完成以下兩個操作:把競爭訪問的資源標識為private;同步哪些修改
變數 的代碼,使用
synchronized 關鍵字同步方法或代碼。當然這不是唯一控制並發安全的途徑。synchronized關鍵字使用說明synchronized只能標記非抽象的方法,不能標識
成員變數 。為了演示同步方法的使用,構建了一個信用卡賬戶,起初信用額為100w,然後模擬透支、存款等多個操作。顯然銀行賬戶User
對象 是個競爭資源,而多個並發操作的是賬戶方法oper(int x),當然應該在此方法上加上同步,並將賬戶的餘額設為私有
變數 ,禁止直接訪問。
工作原理
執行緒是
進程 中的實體,一個進程可以擁有多個執行緒,一個執行緒必須有一個
父進程 。執行緒不擁有
系統資源 ,只有
運行 必須的一些
數據結構 ;它與父進程的其它執行緒共享該進程所擁有的全部資源。執行緒可以創建和
撤消 執行緒,從而實現程式的並發執行。一般,執行緒具有
就緒 、
阻塞 和
運行 三種基本狀態。
在多
中央處理器 的
系統 里,不同執行緒可以同時在不同的中央處理器上
運行 ,甚至當它們屬於同一個
進程 時也是如此。大多數支持多處理器的
作業系統 都提供
編程接口 來讓
進程 可以控制自己的執行緒與各處理器之間的關聯度(affinity)。
進程 可以支持多個執行緒,它們看似同時執行,但互相之間並不同步。一個進程中的多個執行緒共享相同的記憶體地址空間,這就意味著它們可以訪問相同的
變數 和
對象 ,而且它們從同一堆中分配對象。儘管這讓執行緒之間共享信息變得更容易,但您必須小心,確保它們不會妨礙同一
進程 里的其它執行緒。
Java 執行緒工具和
API 看似簡單。但是,編寫有效使用執行緒的複雜程式並不十分容易。因為有多個執行緒共存在相同的記憶體空間中並共享相同的
變數 ,所以您必須小心,確保您的執行緒不會互相干擾。
執行緒屬性
為了正確有效地使用執行緒,必須理解執行緒的各個方面並了解Java
實時系統 。必須知道如何提供執行緒體、執行緒的生命周期、
實時系統 如 何調度執行緒、
執行緒組 、什麼是幽靈執行緒(Demo nThread)。
執行緒體
所有的操作都發生線上程體中,在Java中執行緒體是從Thread
類 繼承的run()方法,或實現Runnable接口的類中的run()方法。當執行緒產生並初始化後,實時系統調用它的run()方法。run()方法內的代碼實現所產生執行緒的行為,它是執行緒的主要部分。
執行緒狀態
附圖表示了執行緒在它的生命周期內的任何時刻所能處的狀態以及引起狀態改變的方法。這圖並不是完整的有限
狀態圖 ,但基本概括了執行緒中比較感興趣和普遍的方面。以下討論有關執行緒生命周期以此為據。
執行緒的狀態
●新執行緒態(New Thread)
產生一個Thread
對象 就生成一個新執行緒。當執行緒處於"新執行緒"狀態時,僅僅是一個空執行緒
對象 ,它還沒有分配到系統資源。因此只能啟動或終止它。任何其他操作都會引發異常。例如,一個執行緒調用了new方法之後,並在調用start方法之前的處於新執行緒狀態,可以調用start和stop方法。
start()方法產生
運行 執行緒所必須的資源,調度執行緒執行,並且調用執行緒的run()方法。在這時執行緒處於可
運行 態。該狀態不稱為
運行 態是因為這時的執行緒並不總是一直占用處理機。特別是對於只有一個處理機的PC而言,任何時刻只能有一個處於可
運行 態的執行緒占用處理 機。Java通過調度來實現
多執行緒 對
處理機 的共享。注意,如果執行緒處於Runnable狀態,它也有可能不在
運行 ,這是因為還有優先權和調度問題。
執行緒的生命狀態與周期 執行緒 ①suspend()方法被調用;
②sleep()方法被調用;
④執行緒處於I/O請求的等待。
●死亡態(Dead)
當run()方法返回,或別的執行緒調用stop()方法,執行緒進入死亡態。通常Applet使用它的stop()方法來終止它產生的所有執行緒。
執行緒的本操作:
派生:執行緒在
進程 內派生出來,它即可由進程派生,也可由執行緒派生。
阻塞 (Block):如果一個執行緒在執行過程中需要等待某個事件發生,則被阻塞。
激活(unblock):如果
阻塞 執行緒的事件發生,則該執行緒被激活並進入
就緒 佇列。
結束(Finish):如果一個執行緒執行結束,它的
暫存器 上下文以及
堆疊 內容等將被釋放。
圖2 執行緒的狀態與操作
執行緒的另一個執行特性是同步。執行緒中所使用的同步控制機制與
進程 中所使用的同步控制機制相同。
執行緒優先權
雖然我們說執行緒是
並發運行 的。然而事實常常並非如此。正如前面談到的,當
系統 中只有一個CPU時,以某種順序在單CPU情況下執行
多執行緒 被稱為調度(scheduling)。Java採用的是一種簡單、固定的調度法,即固定優先權調度。這種算法是根據處於可
運行 態執行緒的相對優先權來實行調度。當執行緒產生時,它繼承原執行緒的優先權。在需要時可對優先權進行修改。在任何時刻,如果有多條執行緒等待
運行 ,
系統 選擇優先權最高的可運行執行緒運行。只有當它停止、自動放棄、或由於某種原因成為非
運行 態低優先權的執行緒才能運行。如果兩個執行緒具有相同的優先權,它們將被交替地
運行 。 Java實時系統的
執行緒調度 算法還是強制性的,在任何時刻,如果一個比其他執行緒優先權都高的執行緒的狀態變為可
運行 態,實時系統將選擇該執行緒來運行。一個應用程式可以通過使用執行緒中的方法setPriority(int),來設定執行緒的優先權大小。
有執行緒進入了就緒狀態,需要有執行緒調度程式來決定何時執行,根據優先權來調度。
執行緒中的join()可以用來邀請其他執行緒先執行(示例代碼如下):
packageorg.thread.test;publicclassJoin01implementsRunnable{publicstaticvoidmain(String[]args){for(inti=0;i<20;i++){if(i==5){Join01j=newJoin01();Threadt=newThread(j);t.setName("被邀請先執行的執行緒.");t.start();try{//邀請這個執行緒,先執行t.join();}catch(InterruptedExceptione){e.printStackTrace();}}System.out.println("沒被邀請的執行緒。"+(i+1));}}publicvoidrun(){for(inti=0;i<10;i++){System.out.println(Thread.currentThread().getName()+(i+1));}}}
yield()告訴系統"把自己的CPU時間讓掉,讓其他執行緒或者自己運行",示例代碼如下:
packageorg.thread.test;
publicclassYield01
{
publicstaticvoidmain(String[]args)
{
YieldFirstyf=newYieldFirst();
YieldSecondys=newYieldSecond();
YieldThirdyt=newYieldThird();
yf.start();ys.start();yt.start();
}
}
classYieldFirstextendsThread
{
@Overridepublicvoidrun()
{
for(inti=0;i<10;i++)
{
System.out.println("第一個執行緒第"+(i+1)+"次運行.");//讓當前執行緒暫停yield();
}
}
}
classYieldSecondextendsThread
{
@Overridepublicvoidrun()
{
for(inti=0;i<10;i++)
{
System.out.println("第二個執行緒第"+(i+1)+"次運行.");//讓當前執行緒暫停yield();
<a href="mailto:}}}classYieldThirdextendsThread{@Overridepublicvoidrun(){for(inti=0;i}
}
}
classYieldThirdextendsThread
{
@Overridepublicvoidrun(){for(inti=0;i<10;i++)
{
System.out.println("第三個執行緒第"+(i+1)+"次運行.");//讓當前執行緒暫停yield();
}
}
幽靈執行緒
任何一個Java執行緒都能成為幽靈執行緒。它是作為運行於同一個
進程 內的
對象 和執行緒的服務提供者。例如,HotJava瀏覽器有一個稱為" 後台圖片閱讀器"的幽靈執行緒,它為需要圖片的
對象 和執行緒從
檔案 系統 或網路讀入圖片。 幽靈執行緒是套用中典型的獨立執行緒。它為同一套用中的其他
對象 和執行緒提供服務。幽靈執行緒的run()方法一般都是無限循環,等待服務請求。
執行緒組
每個Java執行緒都是某個
執行緒組 的成員。
執行緒組 提供一種機制,使得多個執行緒集於一個
對象 內,能對它們實行整體操作。譬如,你能用一個方法調用來啟動或掛起組內的所有執行緒。Java
執行緒組 由ThreadGroup類實現。
當執行緒產生時,可以指定
執行緒組 或由
實時系統 將其放入某個預設的執行緒組內。執行緒只能屬於一個
執行緒組 ,並且當執行緒產生後不能改變它所屬的執行緒組。
多執行緒
對於
多執行緒 的好處這就不多說了。但是,它同樣也帶來了某些新的麻煩。只要在設計程式時特別小心留意,克服這些麻煩並不算太困難。在生成執行緒時必須將執行緒放在指定的執行緒組,也可以放在預設的執行緒組中,預設的就是生成該執行緒的執行緒所在的執行緒組。一旦一個執行緒加入了某個執行緒組,不能被移出這個組。
多執行緒 同步執行緒
許
多執行緒 在執行中必須考慮與其他執行緒之間共享數據或協調
執行狀態 。這就需要同步機制。在Java中每個
對象 都有一把鎖與之對應。但Java不提供單獨的lock和unlock操作。它由高層的結構隱式實現,來保證操作的對應。(然而,我們注意到
Java虛擬機 提供單獨的monito renter和monitorexit指令來實現lock和
unlock操作。) synchronized語句計算一個
對象引用 ,試圖對該對象完成鎖操作,並且在完成鎖操作前停止處理。當鎖操作完成synchronized語句體得到執行。當語句體執行完畢(無論正常或異常),解鎖操作自動完成。作為
面向對象 的語言,synchronized經常與方法連用。一種比較好的辦法是,如果某個
變數 由一個執行緒賦值並由別的執行緒引用或賦值,那么所有對該變數的訪問都必須在某個synchromized語句或synchronized方法內。
執行緒同步 在此假設一種情況:執行緒1與執行緒2都要訪問某個數據區,並且要求執行緒1的訪問先於執行緒2,則這時僅用synchronized是不能解決問題的。這在Unix或Windows NT中可用Simaphore來實現。而Java並不提供。在Java中提供的是wait()和notify()機制。使用如下:
synchronizedmethod_1(/*……*/){//calledbythread1.//accessdataareaavailable=true;notify();}synchronizedmethod_2(/*……*/){//calledbythread2.while(!available)try{wait();//waitfornotify().}catch(InterruptedExceptione){}//accessdataarea}
其中available是類
成員變數 ,置初值為false。
如果在method-2中檢查available為假,則調用wait()。wait()的作用是使執行緒2進入非
運行 態,並且解鎖。在這種情況下,method-1可以被執行緒1調用。當執行notify()後。執行緒2由非
運行 態轉變為可運行態。當method-1調用返回後。執行緒2可重新對該
對象 加鎖,加鎖成功後執行wait()返回後的指令。這種機制也能適用於其他更複雜的情況。
死鎖
如果程式中有幾個
競爭資源 的並發執行緒,那么保證均衡是很重要的。
系統 均衡是指每個執行緒在執行過程中都能充分訪問有限的資源。
系統 中沒有餓死和死鎖的執行緒。Java並不提供對死鎖的檢測機制。對大多數的Java程式設計師來說防止死鎖是一種較好的選擇。最簡單的防止死鎖的方法是對競爭的資源引入序號,如果一個執行緒需要幾個資源,那么它必須先得到小序號的資源,再申請大序號的資源。
最佳化
Java的
多執行緒 安全是基於Lock機制實現的,而Lock的性能往往不如人意。原因是,monitorenter與monitorexit這兩個控制
多執行緒 同步的bytecode
原語 ,是JVM依賴
作業系統 互斥(mutex)來實現的。而互斥是一種會導致執行緒掛起,並在較短的時間內又需要重新調度回原執行緒的,較為消耗資源的操作。所以需要進行對執行緒進行最佳化,提高效率。
輕量級鎖
輕量級鎖(Lightweight Locking)是從Java6開始引入的概念,本意是為了減少
多執行緒 進入互斥的幾率,並不是要替代互斥。它利用了CPU
原語 Compare-And-Swap(CAS,
彙編指令 CMPXCHG),嘗試在進入互斥前,進行補救。下面將詳細介紹JVM如何利用CAS,實現輕量級鎖。
Java Object Model中定義,Object Header是一個2字(1 word = 4 byte)長度的存儲區域。第一個字長度的區域用來標記同步,GC以及hash code等,官方稱之為 mark word。第二個字長度的區域是指向到
對象 的Class。在2個word中,mark word是輕量級鎖實現的關鍵,其結構見右表。
mark word結構 從表中可以看到,state為lightweight locked的那行即為輕量級鎖標記。bitfieds名為指向lock record的
指針 ,這裡的lock record,其實是一塊分配線上程
堆疊 上的空間區域。用於CAS前,拷貝object上的mark word。第三項是重量級鎖標記。後面的狀態單詞很有趣,inflated,譯為膨脹,在這裡意思其實是鎖已升級到OS-level。一般我們只關注第二和第三項即可。lock,unlock與mark word之間的聯繫如右圖所示。在圖中,提到了拷貝object mark word,由於脫離了原始mark word,官方將它冠以displaced前綴,即displaced mark word(置換標記字)。這個displaced mark word是整個輕量級鎖實現的關鍵,在CAS中的compare就需要用它作為條件。
聯繫流程圖 在拷貝完object mark word之後,JVM做了一步交換指針的操作,即流程中第一個橙色矩形框內容所述。將object mark word里的輕量級鎖指針指向lock record所在的stack指針,作用是讓其他執行緒知道,該object monitor已被占用。lock record里的owner指針指向object mark word的作用是為了在接下里的
運行 過程中,識別哪個
對象 被鎖住了。
交換指針 交換指針
最後一步unlock中,我們發現,JVM同樣使用了CAS來驗證object mark word在持有鎖到釋放鎖之間,有無被其他執行緒訪問。如果其他執行緒在持有鎖這段時間裡,嘗試獲取過鎖,則可能自身被掛起,而mark word的重量級鎖指針也會被相應修改。此時,unlock後就需要喚醒被掛起的執行緒。
偏向鎖
Java偏向鎖(Biased Locking)是Java 6引入的一項
多執行緒 最佳化。它通過消除資源無競爭情況下的
同步原語 ,進一步提高了程式的
運行 性能。它與輕量級鎖的區別在於,輕量級鎖是通過CAS來避免進入開銷較大的互斥操作,而偏向鎖是在無競爭場景下完全消除同步,連CAS也不執行(CAS本身仍舊是一種
作業系統 同步原語,始終要在JVM與OS之間來回,有一定的開銷)。所謂的無競爭場景,就是
單執行緒 訪問帶同步的資源或方法。
偏向鎖,顧名思義,它會偏向於第一個訪問鎖的執行緒,如果在接下來的
運行 過程中,該鎖沒有被其他的執行緒訪問,則持有偏向鎖的執行緒將永遠不需要觸發同步。如果在
運行 過程中,遇到了其他執行緒搶占鎖,則持有偏向鎖的執行緒會被掛起,JVM會嘗試消除它身上的偏向鎖,將鎖恢復到標準的輕量級鎖。(偏向鎖只能在
單執行緒 下起作用)。
偏向鎖操作流程 偏向模式和非偏向模式,在mark word表中,主要體現在thread ID欄位是否為空。
掛起持有偏向鎖的執行緒,這步操作類似GC的pause,但不同之處是,它只掛起持有偏向鎖的執行緒(非當前執行緒)。
在搶占模式的橙色區域說明中有提到,指向當前
堆疊 中最近的一個lock record(在輕量級鎖中,lock record是進入鎖前會在stack上創建的一份記憶體空間)。這裡提到的最近的一個lock record,其實就是當前鎖所在的stack frame上分配的lock record。整個步驟是從偏向鎖恢復到輕量級鎖的過程。
偏向鎖也會帶來額外開銷。在JDK6中,偏向鎖是默認啟用的。它提高了
單執行緒 訪問同步資源的性能。
但試想一下,如果你的同步資源或代碼一直都是
多執行緒 訪問的,那么消除偏向鎖這一步驟對你來說就是多餘的。事實上,消除偏向鎖的開銷還是蠻大的。所以在你非常熟悉自己的代碼前提下,大可禁用偏向鎖 -XX:-UseBiasedLocking。
分類
用戶級執行緒:管理過程全部由
用戶程式 完成,作業系統核心心只對
進程 進行管理。
舉例UNIX International 執行緒
UNIX International 執行緒的頭檔案是<thread.h>,僅適用於Sun Solaris作業系統。所以UNIX International執行緒也常被俗稱為Solaris執行緒。
1.創建執行緒
intthr_create(void*stack_base,size_tstack_size,void*(*start_routine)(void*),void*arg,longflags,thread_t*new_thr);
2.等待執行緒
intthr_join(thread_twait_for,thread_t*dead,void**status);
3.掛起執行緒
intthr_suspend(thread_tthr);
4.繼續執行緒
intthr_continue(thread_tthr);
5.退出執行緒
voidthr_exit(void*status);
6.返回當前執行緒的執行緒標識符
thread_tthr_self(void);POSIX執行緒
POSIX執行緒(Pthreads)的頭檔案是<pthread.h>,適用於類Unix作業系統。Windows作業系統並沒有對POSIX執行緒提供原生的支持庫。不過Win32的POSIX執行緒庫的一些實現也還是有的,例如pthreads-w32。
1.創建執行緒
intpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);
2.等待執行緒
intpthread_join(pthread_tthread,void**retval);
3.退出執行緒
voidpthread_exit(void*retval);
4.返回當前執行緒的執行緒標識符
pthread_tpthread_self(void);
5.執行緒取消
intpthread_cancel(pthread_tthread);Win32執行緒
Win32執行緒的頭檔案是<Windows.h>,適用於Windows作業系統。
1.創建執行緒
HANDLEWINAPICreateThread(LPSECURITY_ATTRIBUTESlpThreadAttributes,SIZE_TdwStackSize,LPTHREAD_START_ROUTINElpStartAddress,LPVOIDlpParameter,DWORDdwCreationFlags,LPDWORDlpThreadId);
2.結束本執行緒
VOIDWINAPIExitThread(DWORDdwExitCode);
3.掛起指定的執行緒
DWORDWINAPISuspendThread(HANDLEhThread);
4.恢復指定執行緒運行
DWORDWINAPIResumeThread(HANDLEhThread);
5.等待執行緒運行完畢
DWORDWINAPIWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds);
6.返回當前執行緒的執行緒標識符
DWORDWINAPIGetCurrentThreadId(void);
7.返回當前執行緒的執行緒句柄
HANDLEWINAPIGetCurrentThread(void);C++ 11 執行緒
C++ 11 執行緒的頭檔案是<thread>。
創建執行緒 std::thread::thread(Function&& f, Args&&... args);
等待執行緒結束 std::thread::join();
脫離執行緒控制 std::thread::detach();
交換執行緒 std::thread::swap( thread& other );
C 11 執行緒
C11執行緒的頭檔案是<threads.h>。
C11執行緒僅僅是個“建議標準”,也就是說100%遵守C11標準的C編譯器是可以不支持C11執行緒的。根據C11標準的規定,只要編譯器預定義了__STDC_NO_THREADS__宏,就可以沒有<threads.h>頭檔案,自然也就也沒有下列函式。
1.創建執行緒
intthrd_create(thrd_t*thr,thrd_start_tfunc,void*arg);
2.結束本執行緒
_Noreturnvoidthrd_exit(intres);
3.等待執行緒運行完畢
intthrd_join(thrd_tthr,int*res);
4.返回當前執行緒的執行緒標識符
thrd_tthrd_current();Java執行緒
1)最簡單的情況是,Thread/Runnable的run()方法運行完畢,自行終止。
2)對於更複雜的情況,比如有循環,則可以增加終止標記變數和任務終止的檢查點。
3)最常見的情況,也是為了解決阻塞不能執行檢查點的問題,用中斷來結束執行緒,但中斷只是請求,並不能完全保證執行緒被終止,需要執行執行緒協同處理。
4)IO阻塞和等鎖情況下需要通過特殊方式進行處理。
5)使用Future類的cancel()方法調用。
6)調用執行緒池執行器的shutdown()和shutdownNow()方法。
7)守護執行緒會在非守護執行緒都結束時自動終止。
8)Thread的stop()方法,但已不推薦使用。
執行緒的組成
1)一組代表處理器狀態的CPU暫存器中的內容
2)兩個棧,一個用於當執行緒在核心模式下執行的時候,另一個用於執行緒在用戶模式下執行的時候
3)一個被稱為執行緒局部存儲器(TLS,thread-local storage)的私有儲存區域,各個子系統、運行庫和DLL都會用到該儲存區域
4)一個被稱為執行緒ID(thread ID,執行緒標識符)的唯一標識符(在內部也被稱為客戶ID——進程ID和執行緒ID是在同一個名字空間中生產的,所以它們永遠 不會重疊)
5)有時候執行緒也有它們自己的安全環境,如果多執行緒伺服器應用程式要模仿其客戶的安全環境,則往往可以利用執行緒的安全環境
執行緒狀態變化 (1)創建執行緒
當創建一個新的進程時,也創建一個新的執行緒,進程中的執行緒可以在同一進程中創建新的執行緒中創建新的執行緒。
創建執行緒 (2)終止執行緒
可以正常終止自己,也可能某個執行緒執行錯誤,由其它執行緒強行終止。終止執行緒操作主要負責釋放執行緒占有的暫存器和棧
(3)阻塞執行緒
當執行緒等待每個事件無法運行時,停止其運行。
阻塞執行緒 (4)喚醒執行緒
當阻塞執行緒的事件發生時,將被阻塞的執行緒狀態置為就緒態,將其掛到就緒佇列。進程仍然具有與執行相關的狀態。例如,所謂進程處於“執行”狀態,實際上是指該進程中的某執行緒正在執行。對進程施加的與進程狀態有關的操作,也對其執行緒起作用。例如,把某個進程掛起時,該進程中的所有執行緒也都被掛起,激活也是同樣。