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