java偏向鎖
『壹』 java 的偏向鎖是怎麼實現的
這么專業的問題,還是去萬工信息了解吧,它家做了20多年了,相信一定可以幫助到你!嘻嘻
『貳』 Java處在偏向鎖狀態時,hashcode值存儲在哪
線程獲得鎖,會在a線程的的棧幀里創建lock record(鎖記錄變數),則在鎖對象的對象頭里和lock record里存儲a線程的線程id.以後該線程的進入,就不需要cas操作,只需要判斷是否是當前線程。線程獲取鎖,不會釋放鎖。直到b線程也要競爭該鎖時,a線程才會釋放鎖。
偏向鎖的釋放,需要等待全局安全點(在這個時間點上沒有正在執行的位元組碼),它會首先暫停擁有偏向鎖的線程,然後檢查持有偏向鎖的線程是否還活著,如果線程不處於活動狀態,則將對象頭設置成無鎖狀態。如果線程仍然活著,擁有偏向鎖的棧會被執行,遍歷偏向對象的所記錄。棧幀中的鎖記錄和對象頭的Mark Word要麼重新偏向其他線程,要麼恢復到無鎖,或者標記對象不適合作為偏向鎖。最後喚醒暫停的線程。關閉偏向鎖,通過jvm的參數-XX:UseBiasedLocking=false,則默認會進入輕量級鎖。
『叄』 Java鎖有哪些種類,以及區別
一、公平鎖/非公平鎖
公平鎖是指多個線程按照申請鎖的順序來獲取鎖。
非公平鎖是指多個線程獲取鎖的順序並不是按照申請鎖的順序,有可能後申請的線程比先申請的線程優先獲取鎖。有可能,會造成優先順序反轉或者飢餓現象。
對於Java ReentrantLock而言,通過構造函數指定該鎖是否是公平鎖,默認是非公平鎖。非公平鎖的優點在於吞吐量比公平鎖大。
對於Synchronized而言,也是一種非公平鎖。由於其並不像ReentrantLock是通過AQS的來實現線程調度,所以並沒有任何辦法使其變成公平鎖。
二、可重入鎖
可重入鎖又名遞歸鎖,是指在同一個線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖。說的有點抽象,下面會有一個代碼的示例。
對於Java ReentrantLock而言, 他的名字就可以看出是一個可重入鎖,其名字是Re entrant Lock重新進入鎖。
對於Synchronized而言,也是一個可重入鎖。可重入鎖的一個好處是可一定程度避免死鎖。
synchronized void setA() throws Exception{
Thread.sleep(1000);
setB();
}
synchronized void setB() throws Exception{
Thread.sleep(1000);
}
上面的代碼就是一個可重入鎖的一個特點,如果不是可重入鎖的話,setB可能不會被當前線程執行,可能造成死鎖。
三、獨享鎖/共享鎖
獨享鎖是指該鎖一次只能被一個線程所持有。
共享鎖是指該鎖可被多個線程所持有。
對於Java
ReentrantLock而言,其是獨享鎖。但是對於Lock的另一個實現類ReadWriteLock,其讀鎖是共享鎖,其寫鎖是獨享鎖。
讀鎖的共享鎖可保證並發讀是非常高效的,讀寫,寫讀 ,寫寫的過程是互斥的。
獨享鎖與共享鎖也是通過AQS來實現的,通過實現不同的方法,來實現獨享或者共享。
對於Synchronized而言,當然是獨享鎖。
四、互斥鎖/讀寫鎖
上面講的獨享鎖/共享鎖就是一種廣義的說法,互斥鎖/讀寫鎖就是具體的實現。
互斥鎖在Java中的具體實現就是ReentrantLock
讀寫鎖在Java中的具體實現就是ReadWriteLock
五、樂觀鎖/悲觀鎖
樂觀鎖與悲觀鎖不是指具體的什麼類型的鎖,而是指看待並發同步的角度。
悲觀鎖認為對於同一個數據的並發操作,一定是會發生修改的,哪怕沒有修改,也會認為修改。因此對於同一個數據的並發操作,悲觀鎖採取加鎖的形式。悲觀的認為,不加鎖的並發操作一定會出問題。
樂觀鎖則認為對於同一個數據的並發操作,是不會發生修改的。在更新數據的時候,會採用嘗試更新,不斷重新的方式更新數據。樂觀的認為,不加鎖的並發操作是沒有事情的。
從上面的描述我們可以看出,悲觀鎖適合寫操作非常多的場景,樂觀鎖適合讀操作非常多的場景,不加鎖會帶來大量的性能提升。
悲觀鎖在Java中的使用,就是利用各種鎖。
樂觀鎖在Java中的使用,是無鎖編程,常常採用的是CAS演算法,典型的例子就是原子類,通過CAS自旋實現原子操作的更新。
六、分段鎖
分段鎖其實是一種鎖的設計,並不是具體的一種鎖,對於ConcurrentHashMap而言,其並發的實現就是通過分段鎖的形式來實現高效的並發操作。
我們以ConcurrentHashMap來說一下分段鎖的含義以及設計思想,ConcurrentHashMap中的分段鎖稱為Segment,它即類似於HashMap(JDK7與JDK8中HashMap的實現)的結構,即內部擁有一個Entry數組,數組中的每個元素又是一個鏈表;同時又是一個ReentrantLock(Segment繼承了ReentrantLock)。
當需要put元素的時候,並不是對整個hashmap進行加鎖,而是先通過hashcode來知道他要放在那一個分段中,然後對這個分段進行加鎖,所以當多線程put的時候,只要不是放在一個分段中,就實現了真正的並行的插入。
但是,在統計size的時候,可就是獲取hashmap全局信息的時候,就需要獲取所有的分段鎖才能統計。
分段鎖的設計目的是細化鎖的粒度,當操作不需要更新整個數組的時候,就僅僅針對數組中的一項進行加鎖操作。
七、偏向鎖/輕量級鎖/重量級鎖
這三種鎖是指鎖的狀態,並且是針對Synchronized。在Java
5通過引入鎖升級的機制來實現高效Synchronized。這三種鎖的狀態是通過對象監視器在對象頭中的欄位來表明的。
偏向鎖是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖。降低獲取鎖的代價。
輕量級鎖是指當鎖是偏向鎖的時候,被另一個線程所訪問,偏向鎖就會升級為輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,提高性能。
重量級鎖是指當鎖為輕量級鎖的時候,另一個線程雖然是自旋,但自旋不會一直持續下去,當自旋一定次數的時候,還沒有獲取到鎖,就會進入阻塞,該鎖膨脹為重量級鎖。重量級鎖會讓其他申請的線程進入阻塞,性能降低。
八、自旋鎖
在Java中,自旋鎖是指嘗試獲取鎖的線程不會立即阻塞,而是採用循環的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點是循環會消耗CPU。
典型的自旋鎖實現的例子,可以參考自旋鎖的實現
『肆』 Java中有哪些鎖,區別是什麼
【1】公平所和非公平所。
公平鎖:是指按照申請鎖的順序來獲取鎖,
非公平所:線程獲取鎖的順序不一定按照申請鎖的順序來的。
//默認是不公平鎖,傳入true為公平鎖,否則為非公平鎖
ReentrantLock reentrantLock = new ReetrantLock();
1
2
【2】共享鎖和獨享鎖
獨享鎖:一次只能被一個線程所訪問
共享鎖:線程可以被多個線程所持有。
ReadWriteLock 讀鎖是共享鎖,寫鎖是獨享鎖。
【3】樂觀鎖和悲觀鎖。
樂觀鎖:對於一個數據的操作並發,是不會發生修改的。在更新數據的時候,會嘗試採用更新,不斷重入的方式,更新數據。
悲觀鎖:對於同一個數據的並發操作,是一定會發生修改的。因此對於同一個數據的並發操作,悲觀鎖採用加鎖的形式。悲觀鎖認為,不加鎖的操作一定會出問題,
【4】分段鎖
1.7及之前的concurrenthashmap。並發操作就是分段鎖,其思想就是讓鎖的粒度變小。
【5】偏向鎖是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖。降低獲取鎖的代價
輕量級鎖
重量級鎖
【6】自旋鎖
自旋鎖
『伍』 線程的線程的同步
線程的同步是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):如果阻塞線程的事件發生,則該線程被激活並進入就緒隊列。
調度(schele):選擇一個就緒線程進入執行狀態。
結束(Finish):如果一個線程執行結束,它的寄存器上下文以及堆棧內容等將被釋放。
圖2 線程的狀態與操作
線程的另一個執行特性是同步。線程中所使用的同步控制機制與進程中所使用的同步控制機制相同。
線程優先順序
雖然我們說線程是並發運行的。然而事實常常並非如此。正如前面談到的,當系統中只有一個CPU時,以某種順序在單CPU情況下執行多線程被稱為調度(scheling)。Java採用的是一種簡單、固定的調度法,即固定優先順序調度。這種演算法是根據處於可運行態線程的相對優先順序來實行調度。當線程產生時,它繼承原線程的優先順序。在需要時可對優先順序進行修改。在任何時刻,如果有多條線程等待運行,系統選擇優先順序最高的可運行線程運行。只有當它停止、自動放棄、或由於某種原因成為非運行態低優先順序的線程才能運行。如果兩個線程具有相同的優先順序,它們將被交替地運行。Java實時系統的線程調度演算法還是強制性的,在任何時刻,如果一個比其他線程優先順序都高的線程的狀態變為可運行態,實時系統將選擇該線程來運行。一個應用程序可以通過使用線程中的方法setPriority(int),來設置線程的優先順序大小。
有線程進入了就緒狀態,需要有線程調度程序來決定何時執行,根據優先順序來調度。
線程中的join()可以用來邀請其他線程先執行(示例代碼如下):
packageorg.thread.test;{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是輕量級鎖實現的關鍵,其結構見右表。
從表中可以看到,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.等待線程運行完畢
(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)有時候線程也有它們自己的安全環境,如果多線程伺服器應用程序要模仿其客戶的安全環境,則往往可以利用線程的安全環境
『陸』 深入研究 Java Synchronize 和 Lock 的區別與用法
一、synchronized和lock的用法區別
(1)synchronized(隱式鎖):在需要同步的對象中加入此控制,synchronized可以加在方法上,也可以加在特定代碼塊中,括弧中表示需要鎖的對象。
(2)lock(顯示鎖):需要顯示指定起始位置和終止位置。一般使用ReentrantLock類做為鎖,多個線程中必須要使用一個ReentrantLock類做為對 象才能保證鎖的生效。且在加鎖和解鎖處需要通過lock()和unlock()顯示指出。所以一般會在finally塊中寫unlock()以防死鎖。
二、synchronized和lock性能區別
synchronized是託管給JVM執行的,而lock是java寫的控制鎖的代碼。在Java1.5中,synchronize是性能低效的。因為 這是一個重量級操作,需要調用操作介面,導致有可能加鎖消耗的系統時間比加鎖以外的操作還多。相比之下使用Java提供的Lock對象,性能更高一些。但 是到了Java1.6,發生了變化。synchronize在語義上很清晰,可以進行很多優化,有適應自旋,鎖消除,鎖粗化,輕量級鎖,偏向鎖等等。導致 在Java1.6上synchronize的性能並不比Lock差。
三、synchronized和lock機制區別
(1)synchronized原始採用的是CPU悲觀鎖機制,即線程獲得的是獨占鎖。獨占鎖意味著其 他線程只能依靠阻塞來等待線程釋放鎖。
(2)Lock用的是樂觀鎖方式。所謂樂觀鎖就是,每次不加鎖而是假設沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。樂觀鎖實現的機制就 是CAS操作(Compare and Swap)。