執行緒

執行緒

執行緒(英語:thread)是作業系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條執行緒指的是進程中一個單一順序的控制流,一個進程中可以並發多個執行緒,每條執行緒並行執行不同的任務。在Unix System V及SunOS中也被稱為輕量進程(lightweight processes),但輕量進程更多指核心執行緒(kernel thread),而把用戶執行緒(user thread)稱為執行緒。

執行緒是獨立調度和分派的基本單位。執行緒可以為作業系統核心調度的核心執行緒,如Win32執行緒;由用戶進程自行調度的用戶執行緒,如Linux平台的POSIX Thread;或者由核心與用戶進程,如Windows 7的執行緒,進行混合調度。

同一進程中的多條執行緒將共享該進程中的全部系統資源,如虛擬地址空間,檔案描述符信號處理等等。但同一進程中的多個執行緒有各自的調用棧(call stack),自己的暫存器環境(register context),自己的執行緒本地存儲(thread-local storage)。

一個進程可以有很多執行緒,每條執行緒並行執行不同的任務。

在多核或多CPU,或支持Hyper-threading的CPU上使用多執行緒程式設計的好處是顯而易見,即提高了程式的執行吞吐率。在單CPU單核的計算機上,使用多執行緒技術,也可以把進程中負責I/O處理、人機互動而常被阻塞的部分與密集計算的部分分開來執行,編寫專門的workhorse執行緒執行密集計算,從而提高了程式的執行效率。

基本介紹

  • 中文名:執行緒
  • 外文名:thread
  • 別稱:執行緒;輕量進程
  • 提出者:dozer
  • 套用學科:計算機
  • 多執行緒中:CPU的基本單位
  • 定義:程式執行流的最小單元
發展簡史,適用範圍,特點,與進程比較,守護執行緒,執行緒的同步,執行緒狀態變化,

發展簡史

執行緒的引入:
60年代,在OS中能擁有資源和獨立運行的基本單位是進程,然而隨著計算機技術的發展,進程出現了很多弊端,一是由於進程是資源擁有者,創建、撤消與切換存在較大的時空開銷,因此需要引入輕型進程;二是由於對稱多處理機(SMP)出現,可以滿足多個運行單位,而多個進程並行開銷過大。
因此在80年代,出現了能獨立運行的基本單位——執行緒(Threads)。

適用範圍

1.伺服器中的檔案管理或通信控制
2.前後台處理
3.異步處理

特點

執行緒的使用執行緒的使用
多執行緒OS中,通常是在一個進程中包括多個執行緒,每個執行緒都是作為利用CPU的基本單位,是花費最小開銷的實體。執行緒具有以下屬性。
1)輕型實體
執行緒中的實體基本上不擁有系統資源,只是有一點必不可少的、能保證獨立運行的資源。
執行緒的實體包括程式、數據和TCB。執行緒是動態概念,它的動態特性由執行緒控制塊TCB(Thread Control Block)描述。TCB包括以下信息:
(1)執行緒狀態。
(2)當執行緒不運行時,被保存的現場資源。
(3)一組執行堆疊。
(4)存放每個執行緒的局部變數主存區。
(5)訪問同一個進程中的主存和其它資源。
用於指示被執行指令序列的程式計數器、保留局部變數、少數狀態參數和返回地址等的一組暫存器堆疊
2)獨立調度和分派的基本單位。
在多執行緒OS中,執行緒是能獨立運行的基本單位,因而也是獨立調度和分派的基本單位。由於執行緒很“輕”,故執行緒的切換非常迅速且開銷小(在同一進程中的)。
3)可並發執行。
在一個進程中的多個執行緒之間,可以並發執行,甚至允許在一個進程中所有執行緒都能並發執行;同樣,不同進程中的執行緒也能並發執行,充分利用和發揮了處理機與外圍設備並行工作的能力。
4)共享進程資源。
執行緒執行緒
在同一進程中的各個執行緒,都可以共享該進程所擁有的資源,這首先表現在:所有執行緒都具有相同的地址空間(進程的地址空間),這意味著,執行緒可以訪問該地址空間的每一個虛地址;此外,還可以訪問進程所擁有的已打開檔案、定時器、信號量機構等。由於同一個進程內的執行緒共享記憶體檔案,所以執行緒之間互相通信不必調用核心

與進程比較

執行緒執行緒
進程是資源分配的基本單位。所有與該進程有關的資源,都被記錄在進程控制塊PCB中。以表示該進程擁有這些資源或正在使用它們。
另外,進程也是搶占處理機的調度單位,它擁有一個完整的虛擬地址空間。當進程發生調度時,不同的進程擁有不同的虛擬地址空間,而同一進程內的不同執行緒共享同一地址空間。
與進程相對應,執行緒與資源分配無關,它屬於某一個進程,並與進程內的其他執行緒一起共享進程的資源。
執行緒只由相關堆疊系統棧或用戶棧暫存器和執行緒控制表TCB組成。暫存器可被用來存儲執行緒內的局部變數,但不能存儲其他執行緒的相關變數。
通常在一個進程中可以包含若干個執行緒,它們可以利用進程所擁有的資源。在引入執行緒的作業系統中,通常都是把進程作為分配資源的基本單位,而把執行緒作為獨立運行和獨立調度的基本單位。由於執行緒比進程更小,基本上不擁有系統資源,故對它的調度所付出的開銷就會小得多,能更高效的提高系統內多個程式間並發執行的程度,從而顯著提高系統資源的利用率和吞吐量。因而近年來推出的通用作業系統都引入了執行緒,以便進一步提高系統的並發性,並把它視為現代作業系統的一個重要指標。
執行緒與進程的區別可以歸納為以下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方法。
●可運行態(Runnable)
start()方法產生運行執行緒所必須的資源,調度執行緒執行,並且調用執行緒的run()方法。在這時執行緒處於可運行態。該狀態不稱為運行態是因為這時的執行緒並不總是一直占用處理機。特別是對於只有一個處理機的PC而言,任何時刻只能有一個處於可運行態的執行緒占用處理 機。Java通過調度來實現多執行緒處理機的共享。注意,如果執行緒處於Runnable狀態,它也有可能不在運行,這是因為還有優先權和調度問題。
執行緒的生命狀態與周期執行緒的生命狀態與周期
阻塞/非運行態(Not Runnable)
當以下事件發生時,執行緒進入非運行態。
執行緒執行緒
①suspend()方法被調用;
②sleep()方法被調用;
③執行緒使用wait()來等待條件變數
④執行緒處於I/O請求的等待。
●死亡態(Dead)
當run()方法返回,或別的執行緒調用stop()方法,執行緒進入死亡態。通常Applet使用它的stop()方法來終止它產生的所有執行緒。
執行緒的本操作:
派生:執行緒在進程內派生出來,它即可由進程派生,也可由執行緒派生。
阻塞(Block):如果一個執行緒在執行過程中需要等待某個事件發生,則被阻塞。
激活(unblock):如果阻塞執行緒的事件發生,則該執行緒被激活並進入就緒佇列。
調度(schedule):選擇一個就緒執行緒進入執行狀態
結束(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結構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。
分類
執行緒有兩個基本類型
用戶級執行緒:管理過程全部由用戶程式完成,作業系統核心心只對進程進行管理。
系統級執行緒(核心級執行緒):由作業系統核心進行管理。作業系統核心給應用程式提供相應的系統調用應用程式接口API,以使用戶程式可以創建、執行、撤消執行緒。
舉例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>。
  1. 創建執行緒
    std::thread::thread(Function&& f, Args&&... args);
  2. 等待執行緒結束
    std::thread::join();
  3. 脫離執行緒控制
    std::thread::detach();
  4. 交換執行緒
    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)喚醒執行緒
當阻塞執行緒的事件發生時,將被阻塞的執行緒狀態置為就緒態,將其掛到就緒佇列。進程仍然具有與執行相關的狀態。例如,所謂進程處於“執行”狀態,實際上是指該進程中的某執行緒正在執行。對進程施加的與進程狀態有關的操作,也對其執行緒起作用。例如,把某個進程掛起時,該進程中的所有執行緒也都被掛起,激活也是同樣。

相關詞條

熱門詞條

聯絡我們