<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Evan's Blog

    Java, software development and others.

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      28 隨筆 :: 0 文章 :: 73 評論 :: 0 Trackbacks

    Chapter 3. Data synchronization

    第二章中介紹了如何創(chuàng)建線程對象、啟動和終止線程。但多線程編程的關(guān)鍵在于多個(gè)線程之間數(shù)據(jù)的共享和同步,從這一章開始,將詳細(xì)介紹線程之間數(shù)據(jù)的共享和同步的各種方法。

    3.1 The Synchronized Keywor
    1. synchronized是Java中最基本也最常用的用來編寫多線程安全代碼的關(guān)鍵字,用以保護(hù)對多線程共享的數(shù)據(jù)的操作總是完整的;
    2. Atomic: 當(dāng)一個(gè)操作被定義成原子操作時(shí),意味著該操作在執(zhí)行過程中不會被打斷;原子操作可以由硬件保證或者通過軟件來模擬;
    3. Mutex Lock: 在很多多線程系統(tǒng),通過互斥鎖來保護(hù)的共享數(shù)據(jù)。Java中的任何一個(gè)對象都有一個(gè)與之相關(guān)的鎖,當(dāng)一個(gè)方法被聲明成synchronized時(shí),就表示當(dāng)線程進(jìn)入該方法前,必須獲得相應(yīng)對象的鎖,在執(zhí)行完畢再釋放這個(gè)鎖。從而保證同一時(shí)刻只有一個(gè)線程調(diào)用該對象上的被聲明為synchronized的方法。注意:Java的互斥鎖只能加在對象級上,獲得某個(gè)對象的鎖,并不能保證該對象的屬性和其它非synchronized的方法是線程安全的;也不能保證受保護(hù)的方法里調(diào)用的其它對象是多線程安全的,除非任何調(diào)用這些沒有被保護(hù)的方法或者對象只通過受保護(hù)的方法進(jìn)行調(diào)用。所以,編寫線程安全的代碼關(guān)鍵就在于規(guī)劃方法和對象之間的調(diào)用關(guān)系,并盡量采用相同對象的鎖來進(jìn)行同步控制。

    3.2 The Volatile Keyword
    1. Scope of a Lock: 鎖的作用范圍即獲得和釋放鎖之間的那段時(shí)間。
    2. Java標(biāo)準(zhǔn)雖然聲明存取一個(gè)非long和double變量的操作是原子操作,但由于不同虛擬機(jī)實(shí)現(xiàn)的差異,在多線程環(huán)境下每個(gè)線程可能會保留自己的工作拷貝,而導(dǎo)致變量的值產(chǎn)生沖突。為了避免這種情況的發(fā)生,可以有兩種方法:
      1) 為變量創(chuàng)建聲明為synchronized的setter和getter方法,然后任何調(diào)用(包括在類類部)該變量的地方都通過setter和getter方法;
      2) 采用volatile聲明,確保每次存取這些屬性時(shí)都從主內(nèi)存中讀入或者寫入主內(nèi)存中;
      3) volatile僅僅用于解決Java內(nèi)存模式導(dǎo)致的問題,只能運(yùn)用在對該變量只做一個(gè)單一裝載或?qū)懭氩僮髑以摲椒ǖ钠渌僮鞑⒉灰蕾囋撟兞康淖兓?。如:在一個(gè)循環(huán)體中作為遞增或遞減變量時(shí)就不能使用volatile來解決線程同步的問題。
    3. volatile的使用是有限的,一般而言,僅僅將其作為強(qiáng)制虛擬機(jī)總是從主內(nèi)存讀寫變量的一個(gè)手段,或者某些需要其參數(shù)聲明為volatile的函數(shù)。

    3.3 More on Race Conditions
    本節(jié)以打字游戲中顯示成績的例子來解釋了可能存在的race condition。關(guān)鍵要注意以下幾點(diǎn):
    1. 操作系統(tǒng)會隨機(jī)的切換多個(gè)線程的運(yùn)行,因此當(dāng)多個(gè)線程調(diào)用同一個(gè)方法時(shí),可能在任何地方被暫停而將控制權(quán)交給另外的線程;
    2. 為了減少被誤用的可能,總是假設(shè)方法有可能被多個(gè)線程調(diào)用;
    3. 鎖僅僅與某個(gè)特定實(shí)例相關(guān),而與任何方法和類都無關(guān),這一點(diǎn)當(dāng)需要存取類屬性或方法時(shí)要特別注意;
    4. 任何時(shí)候只有一個(gè)線程能夠運(yùn)行某個(gè)類中一個(gè)被聲明為synchronized的靜態(tài)方法;一個(gè)線程只能運(yùn)行某個(gè)特定實(shí)例中一個(gè)被聲明為synchronized的非靜態(tài)方法。

    3.4 Explicit Locking
    1. 學(xué)過Win32下編寫多線程的朋友剛開始可能會被Java的Synchronized關(guān)鍵詞搞糊涂。因?yàn)镴ava中的任何一個(gè)對象都有一個(gè)與之相關(guān)的鎖,而不象在Win32下要先定義一個(gè)互斥量,然后再調(diào)用一個(gè)函數(shù)進(jìn)入或者離開互斥區(qū)域。在JDK 1.5以后也開始提供這種顯示聲明的鎖。JDK 1.5中定義了一個(gè)Lock接口和一些類,允許程序員顯示的使用鎖對象。
    2. 在Lock接口里有兩個(gè)方法:lock()和unlock()用來獲取和釋放鎖對象,從而保證受保護(hù)的代碼區(qū)域是線程安全的。
    3. 使用鎖對象的一個(gè)好處在于可以被保存、傳遞和拋棄,以在比較復(fù)雜的多線程應(yīng)用中使用統(tǒng)一的鎖。
    在使用鎖對象時(shí),總是將lock()和unlock()調(diào)用包含在try/finally塊中,以防止運(yùn)行時(shí)異常的拋出而導(dǎo)致死鎖的情況。

    3.5 Lock Scope
    利用lock()和unlock()方法,我們可以在任何地方使用它們,從一行代碼到跨越多個(gè)方法和對象,這樣就能根據(jù)程序設(shè)計(jì)需要來定義鎖的作用(scope of lock)范圍,而不是象以前局限在對象的層次上。

    3.5.1 Synchronized Blocks

    1. 利用synchronized關(guān)鍵字也能建立同步塊,而不一定非得同步整個(gè)方法。
    2. 同步一段代碼時(shí),需要明確的指定獲取哪個(gè)對象的鎖(這就類似于鎖對象了),這樣,就可以在多個(gè)方法或?qū)ο笾泄蚕磉@個(gè)鎖對象。

    3.6 Choosing a Locking Mechanism
    使用鎖對象還是同步關(guān)鍵字(synchronized),這個(gè)取決于開發(fā)員自己。使用synchronized比較簡單,但相對而言,比較隱晦,在比較復(fù)雜的情況下(如要同時(shí)同步靜態(tài)和非靜態(tài)方法時(shí)),沒有鎖對象來得直觀和統(tǒng)一。一般而言,synchronized簡單,易于使用;但同時(shí)相對而言效率較低,且不能跨越多個(gè)方法。

    3.6.1 The Lock Interface
    public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit)
    throws InterruptedException;
    void unlock();
    Condition newCondition();
    }
    其中的tryLock()和tryLock(long, TimeUnit)將嘗試獲取鎖對象,如果不能獲取或在指定時(shí)間內(nèi)不能獲取,將立即返回。調(diào)用者可以根據(jù)返回值來判斷是否獲得了鎖對象以做進(jìn)一步的操作。

    3.7 Nested Locks
    1. 在一個(gè)同步方法內(nèi)調(diào)用同一個(gè)對象上的另外的同步方法的情況,稱之為嵌套鎖(nested locking)。系統(tǒng)將自動執(zhí)行嵌套的同步方法,而無須等待鎖的釋放。因此,有的時(shí)候,即使一些私有方法僅僅被已同步的方法調(diào)用,我們也給其加上synchronized關(guān)鍵字,以減少后續(xù)維護(hù)時(shí)可能產(chǎn)生的誤導(dǎo)。
    2. ReenterantLock類也支持嵌套鎖。在ReenterantLock類維持一個(gè)計(jì)數(shù)器,只有當(dāng)這個(gè)計(jì)數(shù)器為0時(shí),才會釋放鎖。注意:這個(gè)特性是ReenterantLock類的特性,而不是所有實(shí)現(xiàn)Lock接口的類的特性。
    3. 需要支持嵌套鎖的一個(gè)原因是方法之間交叉調(diào)用(cross-calling)。設(shè)想對象a的方法M1調(diào)用對象b的方法N1,然后N1再調(diào)用對象a的方法M2,而M1和M2都是同步方法,如果不支持嵌套鎖,則N1將在調(diào)用M2時(shí)等待M1釋放鎖,而M1則由于N1沒有返回永遠(yuǎn)也不會釋放鎖,這樣就產(chǎn)生了死鎖。
    4. synchronized和Lock接口并沒有提供鎖對象被嵌套獲取的次數(shù),但ReentrantLock則提供了這樣一種機(jī)制:
    public class ReentrantLock implements Lock {
    public int getHoldCount();
    public boolean isLocked();
    public boolean isHeldByCurrentThread();
    public int getQueueLength();
    ...
    }
    其中:
        1) getHoldCount()返回當(dāng)前線程的獲取次數(shù),返回0并不表示該鎖是可獲取的,有可能沒有被當(dāng)前線程獲得;
        2) isLocked()判斷該鎖對象是否被任何線程獲得;
        3) isHeldByCurrentThread()判斷是否由當(dāng)前線程獲得;
        4) getQueueLength()用來估計(jì)當(dāng)前有多少線程在等待獲取這個(gè)鎖對象。

    3.8 Deadlock
    介紹了死鎖的概念,并修改例子代碼來演示deadlock的產(chǎn)生。死鎖一般產(chǎn)生在多個(gè)線程在多個(gè)鎖上同步時(shí)產(chǎn)生的;當(dāng)然,多個(gè)線程在判斷多個(gè)條件的時(shí)候,也有可能產(chǎn)生死鎖。

    3.9 Lock Fairness
    1. Java里鎖的獲取機(jī)制依賴于底層多線程系統(tǒng)的實(shí)現(xiàn),并不保證一個(gè)特定的順序;
    2. ReentrantLock類提供一個(gè)先進(jìn)先出(first-in-first-out)的獲取鎖的選項(xiàng)(在創(chuàng)建鎖對象時(shí)傳入true值)。
    文章來源:http://blog.csdn.net/evanwhj/archive/2006/03/05/616068.aspx
    posted on 2006-03-05 23:25 Evan 閱讀(504) 評論(0)  編輯  收藏 所屬分類: Java筆記
    主站蜘蛛池模板: 亚洲AV福利天堂一区二区三| 最近免费中文字幕大全视频| 亚洲成AⅤ人影院在线观看| 亚洲精品无码专区| 在线观看永久免费视频网站| 亚洲熟女精品中文字幕| 免费无码又爽又刺激高潮| 亚洲中文字幕久久久一区| 午夜电影免费观看| 国产精品亚洲色婷婷99久久精品| 日韩伦理片电影在线免费观看| 亚洲国产欧美一区二区三区| 免费国产在线观看不卡| 曰韩无码AV片免费播放不卡| 国产偷窥女洗浴在线观看亚洲| a视频在线免费观看| 亚洲免费福利视频| 全免费a级毛片免费看无码| 久久亚洲精品无码av| 亚洲а∨天堂久久精品| 中国国产高清免费av片| 久久夜色精品国产噜噜亚洲AV| 69xx免费观看视频| 在线观看亚洲专区| 国产成人A亚洲精V品无码| 67pao强力打造高清免费| 久久久国产亚洲精品| 亚洲成人高清在线| 日韩av无码久久精品免费| 亚洲一区在线免费观看| yy6080亚洲一级理论| 久久精品免费观看| 中文字幕无码亚洲欧洲日韩| 无码不卡亚洲成?人片| 男的把j放进女人下面视频免费| jlzzjlzz亚洲jzjzjz| 亚洲成网777777国产精品| 久久久久久久99精品免费| 亚洲av综合av一区二区三区| 中文亚洲AV片在线观看不卡| 四虎永久在线观看免费网站网址 |