wait():使一個(gè)線(xiàn)程處于等待狀態(tài),并且釋放所持有的對象的lock。
sleep():使一個(gè)正在運行的線(xiàn)程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調用此方法要捕捉InterruptedException異常
notify():?jiǎn)拘岩粋€(gè)處于等待狀態(tài)的線(xiàn)程,注意的是在調用此方法的時(shí)候,并不能確切的喚醒某一個(gè)等待狀態(tài)的線(xiàn)
程,而是由JVM確定喚醒哪個(gè)線(xiàn)程,而且不是按優(yōu)先級。
Allnotity():?jiǎn)拘阉刑幦氲却隣顟B(tài)的線(xiàn)程,注意并不是給所有喚醒線(xiàn)程一個(gè)對象的鎖,而是讓它們競爭。
實(shí)現同步機制有兩個(gè)方法:
1、同步代碼塊:
synchronized(同一個(gè)數據){} 同一個(gè)數據:就是N條線(xiàn)程同時(shí)訪(fǎng)問(wèn)一個(gè)數據。
2、同步方法:
public synchronized 數據返回類(lèi)型 方法名(){}
就是使用 synchronized 來(lái)修飾某個(gè)方法,則該方法稱(chēng)為同步方法。對于同步方法而言,無(wú)需顯示指定同步監視器,同步方法的同步監視器是 this 也就是該對象的本身(這里指的對象本身有點(diǎn)含糊,其實(shí)就是調用該同步方法的對象)通過(guò)使用同步方法,可非常方便的將某類(lèi)變成線(xiàn)程安全的類(lèi),具有如下特征:
1,該類(lèi)的對象可以被多個(gè)線(xiàn)程安全的訪(fǎng)問(wèn)。
2,每個(gè)線(xiàn)程調用該對象的任意方法之后,都將得到正確的結果。
3,每個(gè)線(xiàn)程調用該對象的任意方法之后,該對象狀態(tài)依然保持合理狀態(tài)。
注:synchronized關(guān)鍵字可以修飾方法,也可以修飾代碼塊,但不能修飾構造器,屬性等。
實(shí)現同步機制注意以下幾點(diǎn): 安全性高,性能低,在多線(xiàn)程用。性能高,安全性低,在單線(xiàn)程用。
1,不要對線(xiàn)程安全類(lèi)的所有方法都進(jìn)行同步,只對那些會(huì )改變共享資源方法的進(jìn)行同步。
2,如果可變類(lèi)有兩種運行環(huán)境,當線(xiàn)程環(huán)境和多線(xiàn)程環(huán)境則應該為該可變類(lèi)提供兩種版本:線(xiàn)程安全版本和線(xiàn)程不安全版本(沒(méi)有同步方法和同步塊)。在單線(xiàn)程中環(huán)境中,使用線(xiàn)程不安全版本以保證性能,在多線(xiàn)程中使用線(xiàn)程安全版本.
線(xiàn)程有可能和其他線(xiàn)程共享一些資源,比如,內存,文件,數據庫等。
當多個(gè)線(xiàn)程同時(shí)讀寫(xiě)同一份共享資源的時(shí)候,可能會(huì )引起沖突。這時(shí)候,我們需要引入線(xiàn)程“同步”機制,即各位線(xiàn)程之間要有個(gè)先來(lái)后到,不能一窩蜂擠上去搶作一團。
線(xiàn)程同步的真實(shí)意思和字面意思恰好相反。線(xiàn)程同步的真實(shí)意思,其實(shí)是“排隊”:幾個(gè)線(xiàn)程之間要排隊,一個(gè)一個(gè)對共享資源進(jìn)行操作,而不是同時(shí)進(jìn)行操作。
線(xiàn)程同步的方法
(1)wait():使一個(gè)線(xiàn)程處于等待狀態(tài),并且釋放所持有的對象的lock。
(2)sleep():使一個(gè)正在運行的線(xiàn)程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調用此方法要捕捉
interruptedexception異常。
(3)notify():?jiǎn)拘岩粋€(gè)處于等待狀態(tài)的線(xiàn)程,注意的是在調用此方法的時(shí)候,并不能確切的
喚醒某一個(gè)等待狀態(tài)的線(xiàn)程,而是由jvm確定喚醒哪個(gè)線(xiàn)程,而且不是按優(yōu)先級。
(4)notityall ():?jiǎn)拘阉刑幦氲却隣顟B(tài)的線(xiàn)程,注意并不是給所有喚醒線(xiàn)程一個(gè)對象的鎖,
而是讓它們競爭
1 wait方法:
該方法屬于Object的方法,wait方法的作用是使得當前調用wait方法所在部分(代碼塊)的線(xiàn)程停止執行,并釋放當前獲得的調用wait所在的代碼塊的鎖,并在其他線(xiàn)程調用notify或者notifyAll方法時(shí)恢復到競爭鎖狀態(tài)(一旦獲得鎖就恢復執行)。
調用wait方法需要注意幾點(diǎn):
第一點(diǎn):wait被調用的時(shí)候必須在擁有鎖(即synchronized修飾的)的代碼塊中。
第二點(diǎn):恢復執行后,從wait的下一條語(yǔ)句開(kāi)始執行,因而wait方法總是應當在while循環(huán)中調用,以免出現恢復執行后繼續執行的條件不滿(mǎn)足卻繼續執行的情況。
第三點(diǎn):若wait方法參數中帶時(shí)間,則除了notify和notifyAll被調用能激活處于wait狀態(tài)(等待狀態(tài))的線(xiàn)程進(jìn)入鎖競爭外,在其他線(xiàn)程中interrupt它或者參數時(shí)間到了之后,該線(xiàn)程也將被激活到競爭狀態(tài)。
第四點(diǎn):wait方法被調用的線(xiàn)程必須獲得之前執行到wait時(shí)釋放掉的鎖重新獲得才能夠恢復執行。
2 notify方法和notifyAll方法:
notify方法通知調用了wait方法,但是尚未激活的一個(gè)線(xiàn)程進(jìn)入線(xiàn)程調度隊列(即進(jìn)入鎖競爭),注意不是立即執行。并且具體是哪一個(gè)線(xiàn)程不能保證。另外一點(diǎn)就是被喚醒的這個(gè)線(xiàn)程一定是在等待wait所釋放的鎖。
notifyAll方法則喚醒所有調用了wait方法,尚未激活的進(jìn)程進(jìn)入競爭隊列。
3 synchronized關(guān)鍵字:
第一點(diǎn):synchronized用來(lái)標識一個(gè)普通方法時(shí),表示一個(gè)線(xiàn)程要執行該方法,必須取得該方法所在的對象的鎖。
第二點(diǎn):synchronized用來(lái)標識一個(gè)靜態(tài)方法時(shí),表示一個(gè)線(xiàn)程要執行該方法,必須獲得該方法所在的類(lèi)的類(lèi)鎖。
第三點(diǎn):synchronized修飾一個(gè)代碼塊。類(lèi)似這樣:synchronized(obj) { //code。. }。表示一個(gè)線(xiàn)程要執行該代碼塊,必須獲得obj的鎖。這樣做的目的是減小鎖的粒度,保證當不同塊所需的鎖不沖突時(shí)不用對整個(gè)對象加鎖。利用零長(cháng)度的byte數組對象做obj非常經(jīng)濟。
線(xiàn)程同步的方式包括:互斥鎖、讀寫(xiě)鎖、條件變量、信號量和令牌。
以Java語(yǔ)言為例:用synchronized關(guān)鍵字修飾同步方法。同步有幾種實(shí)現方法分別是synchronized,wait與notifywait():使一個(gè)線(xiàn)程處于等待狀態(tài),并且釋放所持有的對象的lock。
sleep():使一個(gè)正在運行的線(xiàn)程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調用此方法要捕捉InterruptedException異常。notify():?jiǎn)拘岩粋€(gè)處于等待狀態(tài)的線(xiàn)程,注意的是在調用此方法的時(shí)候,并不能確切的喚醒某一個(gè)等待狀態(tài)的線(xiàn)程,而是由JVM確定喚醒哪個(gè)線(xiàn)程,而且不是按優(yōu)先級。
Allnotity():?jiǎn)拘阉刑幦氲却隣顟B(tài)的線(xiàn)程,注意并不是給所有喚醒線(xiàn)程一個(gè)對象的鎖,而是讓它們競爭。同步是多線(xiàn)程中的重要概念。
同步的使用可以保證在多線(xiàn)程運行的環(huán)境中,程序不會(huì )產(chǎn)生設計之外的錯誤結果。同步的實(shí)現方式有兩種,同步方法和同步塊,這兩種方式都要用到synchronized關(guān)鍵字。
給一個(gè)方法增加synchronized修飾符之后就可以使它成為同步方法,這個(gè)方法可以是靜態(tài)方法和非靜態(tài)方法,但是不能是抽象類(lèi)的抽象方法,也不能是接口中的接口方法。下面代碼是一個(gè)同步方法的示例:public synchronized void aMethod() { // do something } public static synchronized void anotherMethod() { // do something } 線(xiàn)程在執行同步方法時(shí)是具有排它性的。
當任意一個(gè)線(xiàn)程進(jìn)入到一個(gè)對象的任意一個(gè)同步方法時(shí),這個(gè)對象的所有同步方法都被鎖定了,在此期間,其他任何線(xiàn)程都不能訪(fǎng)問(wèn)這個(gè)對象的任意一個(gè)同步方法,直到這個(gè)線(xiàn)程執行完它所調用的同步方法并從中退出,從而導致它釋放了該對象的同步鎖之后。在一個(gè)對象被某個(gè)線(xiàn)程鎖定之后,其他線(xiàn)程是可以訪(fǎng)問(wèn)這個(gè)對象的所有非同步方法的。
同步塊是通過(guò)鎖定一個(gè)指定的對象,來(lái)對同步塊中包含的代碼進(jìn)行同步;而同步方法是對這個(gè)方法塊里的代碼進(jìn)行同步,而這種情況下鎖定的對象就是同步方法所屬的主體對象自身。如果這個(gè)方法是靜態(tài)同步方法呢?那么線(xiàn)程鎖定的就不是這個(gè)類(lèi)的對象了,也不是這個(gè)類(lèi)自身,而是這個(gè)類(lèi)對應的java.lang.Class類(lèi)型的對象。
同步方法和同步塊之間的相互制約只限于同一個(gè)對象之間,所以靜態(tài)同步方法只受它所屬類(lèi)的其它靜態(tài)同步方法的制約,而跟這個(gè)類(lèi)的實(shí)例(對象)沒(méi)有關(guān)系。
wait():使一個(gè)線(xiàn)程處于等待狀態(tài),并且釋放所持有的對象的lock。
sleep():使一個(gè)正在運知行的線(xiàn)程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調用此道方法要捕捉InterruptedException異常。notify():?jiǎn)拘岩粋€(gè)處于等待狀態(tài)的線(xiàn)程,注意的是在調用此方法的時(shí)候,并不專(zhuān)能確切的喚醒某一個(gè)等待狀態(tài)的線(xiàn)程,而是由JVM確定喚醒哪個(gè)線(xiàn)程,而且不是按優(yōu)先級。
Allnotity():?jiǎn)拘阉刑幦氲却隣顟B(tài)的線(xiàn)程,注意并不是給所有喚醒線(xiàn)程一個(gè)對象的鎖,而是讓屬它們競爭。
進(jìn)程中線(xiàn)程同步的四種常用方式: 1、臨界區(CCriticalSection) 當多個(gè)線(xiàn)程訪(fǎng)問(wèn)一個(gè)獨占性共享資源時(shí),可以使用臨界區對象。
擁有臨界區的線(xiàn)程可以訪(fǎng)問(wèn)被保護起來(lái)的資源或代碼段,其他線(xiàn)程若想訪(fǎng)問(wèn),則被掛起,直到擁有臨界區的線(xiàn)程放棄臨界區為止。具體應用方式: 1、定義臨界區對象CcriticalSection g_CriticalSection; 2、在訪(fǎng)問(wèn)共享資源(代碼或變量)之前,先獲得臨界區對象,g_CriticalSection.Lock(); 3、訪(fǎng)問(wèn)共享資源后,則放棄臨界區對象,g_CriticalSection.Unlock(); 2、事件(CEvent) 事件機制,則允許一個(gè)線(xiàn)程在處理完一個(gè)任務(wù)后,主動(dòng)喚醒另外一個(gè)線(xiàn)程執行任務(wù)。
比如在某些網(wǎng)絡(luò )應用程序中,一個(gè)線(xiàn)程如A負責偵聽(tīng)通信端口,另外一個(gè)線(xiàn)程B負責更新用戶(hù)數據,利用事件機制,則線(xiàn)程A可以通知線(xiàn)程B何時(shí)更新用戶(hù)數據。每個(gè)Cevent對象可以有兩種狀態(tài):有信號狀態(tài)和無(wú)信號狀態(tài)。
Cevent類(lèi)對象有兩種類(lèi)型:人工事件和自動(dòng)事件。 自動(dòng)事件對象,在被至少一個(gè)線(xiàn)程釋放后自動(dòng)返回到無(wú)信號狀態(tài); 人工事件對象,獲得信號后,釋放可利用線(xiàn)程,但直到調用成員函數ReSet()才將其設置為無(wú)信號狀態(tài)。
在創(chuàng )建Cevent對象時(shí),默認創(chuàng )建的是自動(dòng)事件。 1、1234CEvent(BOOL bInitiallyOwn=FALSE, BOOL bManualReset=FALSE, LPCTSTR lpszName=NULL, LPSECURITY_ATTRIBUTES lpsaAttribute=NULL); bInitiallyOwn:指定事件對象初始化狀態(tài),TRUE為有信號,FALSE為無(wú)信號; bManualReset:指定要創(chuàng )建的事件是屬于人工事件還是自動(dòng)事件。
TRUE為人工事件,FALSE為自動(dòng)事件; 后兩個(gè)參數一般設為NULL,在此不作過(guò)多說(shuō)明。 2、BOOL CEvent::SetEvent(); 將Cevent類(lèi)對象的狀態(tài)設置為有信號狀態(tài)。
如果事件是人工事件,則Cevent類(lèi)對象保持為有信號狀態(tài),直到調用成員函數ResetEvent()將其重新設為無(wú)信號狀態(tài)時(shí)為止。如果為自動(dòng)事件,則在SetEvent()后將事件設置為有信號狀態(tài),由系統自動(dòng)重置為無(wú)信號狀態(tài)。
3、BOOL CEvent::ResetEvent(); 將事件的狀態(tài)設置為無(wú)信號狀態(tài),并保持該狀態(tài)直至SetEvent()被調用為止。由于自動(dòng)事件是由系統自動(dòng)重置,故自動(dòng)事件不需要調用該函數。
一般通過(guò)調用WaitForSingleObject()函數來(lái)監視事件狀態(tài)。 3、互斥量(CMutex) 互斥對象和臨界區對象非常相似,只是其允許在進(jìn)程間使用,而臨界區只限制與同一進(jìn)程的各個(gè)線(xiàn)程之間使用, 但是更節省資源,更有效率。
4、信號量(CSemphore) 當需要一個(gè)計數器來(lái)限制可以使用某共享資源的線(xiàn)程數目時(shí),可以使用“信號量”對象。CSemaphore類(lèi)對象保存了對當前訪(fǎng)問(wèn)某一個(gè)指定資源的線(xiàn)程的計數值,該計數值是當前還可以使用該資源的線(xiàn)程數目。
如果這個(gè)計數達到了零,則所有對這個(gè)CSemaphore類(lèi)對象所控制的資源的訪(fǎng)問(wèn)嘗試都被放入到一個(gè)隊列中等待,直到超時(shí)或計數值不為零為止。 CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL ); lInitialCount:信號量對象的初始計數值,即可訪(fǎng)問(wèn)線(xiàn)程數目的初始值; lMaxCount:信號量對象計數值的最大值,該參數決定了同一時(shí)刻可訪(fǎng)問(wèn)由信號量保護的資源的線(xiàn)程最大數目; 后兩個(gè)參數在同一進(jìn)程中使用一般為NULL,不作過(guò)多討論; 一般是將當前可用資源計數設置為最大資源計數,每增加一個(gè)線(xiàn)程對共享資源的訪(fǎng)問(wèn),當前可用資源計數就減1,只要當前可用資源計數大于0,就可以發(fā)出信號量信號。
如果為0,則放入一個(gè)隊列中等待。線(xiàn)程在處理完共享資源后,應在離開(kāi)的同時(shí)通過(guò)ReleaseSemaphore()函數將當前可用資源數加1。
聲明:本網(wǎng)站尊重并保護知識產(chǎn)權,根據《信息網(wǎng)絡(luò )傳播權保護條例》,如果我們轉載的作品侵犯了您的權利,請在一個(gè)月內通知我們,我們會(huì )及時(shí)刪除。
蜀ICP備2020033479號-4 Copyright ? 2016 學(xué)習?shū)B(niǎo). 頁(yè)面生成時(shí)間:2.619秒