多線程編程和java的抽象

java線程狀態http://my.oschina.net/mingdongcheng/blog/139263

死鎖:彼此都在等對方釋放的鎖,結果永遠等下去

阻塞:因爲缺少某個條件,導致讓出了cpu,並且不再是就緒狀態。

類型分爲等待阻塞(o.wait)對應waitting queue、同步阻塞(lock)對應lock pool、其他阻塞(sleep、join、同步IO,滿足後自動變成就緒)

 

一、OS的封裝

        OS支持進程,支持cpu調度,所以多進程的同步由OS來實現(比如進程堵在磁盤訪問的隊列上),

但是同一個進程內的多線程,屬於應用的範疇,所以需要程序員自己來實現

二、Linux對多線程的支持

        linux沒有單獨實現線程,而是直接使用輕量級進程來模擬的(實現了pthread的語義),利用copyOnWrite來提高效率,這樣進程間通信的方式,可以用在線程同步。linux內核提供的同步的工具包括:

1、原子操作 2、自旋鎖(spin lock)循環詢問和等待(避免被換出和換入打破cache等優化)3、mutex 4、readWriteLock  5、condition 6、semaphore

三、pthread

        POSIX threads 是類unix操作系統的多線程標準API(windows有移植版本),提供的同步方式包括 Mutex、condition、semaphore

1、Mutex 保護的區域(代碼片段),一次只會進入一個線程(面向過程),相關api是lock, unlock

2、condition 條件變量是一種同步機制,允許線程掛起,直到共享數據上的某些條件得到滿足。與互斥鎖不同,條件變量是用來等待而不是用來上鎖的。條件變量用來自動阻塞一個線程,直到某特殊情況發生爲止。這種環境下 條件本身同時被多個線程訪問,所以需要加鎖保護條件。線程在改變條件狀態前先要鎖住互斥量。條件變量使我們可以睡眠等待某種條件出現。條件變量是利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起;另一個線程使"條件成立"(給出條件成立信號)。條件的檢測是在互斥鎖的保護下進行的。如果一個條件爲假,一個線程自動阻塞,並釋放等待狀態改變的互斥鎖。如果另一個線程改變了條件,它發信號給關聯的條件變量,喚醒一個或多個等待它的線程,重新獲得互斥鎖,重新評價條件。如果兩進程共享可讀寫的內存,條件變量可以被用來實現這兩進程間的線程同步。條件變量要和互斥量相聯結,以避免出現條件競爭--一個線程預備等待一個條件變量,當它在真正進入等待之前,另一個線程恰好觸發了該條件。(目的是等到後再執行,現在則永遠等不到信號)

wait(線程釋放mutex,被掛起到等待隊列,不再佔用cpu,被signal喚起前,會自動加鎖;前面的過程自動進行) 

signal 喚醒同一個condition上wait的線程

3、semaphore 相當於封裝了mutex+condition,且支持多個條件值(不需要同步),相關api wait post

 

四、java的封裝

        java對併發的封裝有幾個層次,包括 

1、基礎的lock、condition、原子操作,分別在java.util.concurrent.locks和java.util.concurrent.atomic

2、Thread類,syncronized(悲觀鎖,阻塞) volatile(修改的可見性) 等關鍵字

3、併發的數據結構,阻塞隊列、線程池、信號量等併發的組件(java.util.concurrent)

4、Thread類中幾個方法的含義

join 獲得某個線程的鎖,之後wait,所以可以實現前一個線程結束後才執行下一個

wait(屬於Object) 阻塞到當前對象,釋放當前Object上的鎖

static void yield() 暫停當前正在執行的線程對象,並執行其他線程。不釋放鎖

static void sleep(long millisec) 讓出cpu,不釋放鎖

5、實際中需要注意的

syncronized太消極,考慮用原子類型、讀寫鎖等來代替

注意減少鎖住的粒度,考慮使用ConcurrentHashMap等數據結構

考慮使用不基於鎖的同步機制(硬件的指令支持)

 

五、syncronized封裝的隱式鎖與顯示的Lock的區別(後者更靈活,進而在特定情況下更高效,缺點是使用複雜)

1、可中斷申請 2、嘗試型申請 3、可以插隊提高吞吐率 4、可以精確喚醒(signal)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章