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