* 解決髒讀
* 造成髒讀的原因是在寫入資料(set)的時候,呼叫了讀取資料(get)的方法,造成讀到修改的資料的現象。
* 解決的辦法是:使用synchronize同時對get方法和set方法加鎖,這樣set的時候就無法get
* 鎖重入
* 概念:對於拿到某個鎖的執行緒,它由可能再拿到其他的鎖。對於它剛執行完並釋放的鎖,也有可能再次立即獲得
* 對於同步塊中拋異常的情況
* 如果同步塊執行過程中捕獲到了異常,如果由對其進行處理,則同步不會被打斷,程式繼續執行。如果丟擲了異常,則同步塊會被打斷,執行緒擁有的該物件鎖也會被釋放
* 對於同步物件的要求
* 同步物件的引用只要沒有變化,那麼執行緒就視同步物件始終沒變,它始終持有同乙個物件鎖,如果同步的物件引用發生改變,那麼執行緒就認為它前後所持有的物件鎖是不一樣的
* 盡量不要對string常量加鎖
* 原因:可能會出現死迴圈,字串常量在常量池中只有乙份物件,所以一把鎖永遠都會被同乙個執行緒拿著不放
* vo la tile關鍵字
* 作用:讓某個變數在多個執行緒間可見
* 原理:
1. 對於執行緒,執行緒共享同乙個堆空間(主記憶體),這個堆空間儲存著實際的物件。
2. 當某個執行緒啟動並訪問共享的堆空間變數的時候,它會開闢一塊屬於自己的空間,然後把堆空間中的變數複製乙份放置到自己的空間中,然後讀和取都對自己空間中的變數進行訪問。至於執行緒何時把寫如自己空間中的變數寫到堆空間中,我們是無法控制的。
3. 當兩個執行緒同時讀取共享堆空間中的變數,它們會將變數複製乙份,放到各自空間中。如果此時的變數被volatile修飾,那麼:[劃重點]
若變數被volatile修飾,當該變數的值改變時,會強制所有執行緒執行引擎去主記憶體,也就是堆空間重新讀取乙份
* 注意:volatile雖然具備可見性,但是不具備原子性,即當乙個方法中由多個操作,多執行緒併發訪問的時候可能會被打斷
* 例項:volatiletest.runthread
* atomicinteger
* 具備原子性的integer,保證在操作的時候,型別一直保持原子性
* 靜態內部類實現單例模式
* **:
public class innersingleton
// 宣告乙個靜態方法來返回這個例項物件
public static singleton getsingleton()
}* 為什麼要使用靜態內部類來實現單例?
答:使用這種方法可以解決普通的餓漢式和懶漢式的弊端,對多執行緒併發訪問的支援非常友好。
為什麼不使用餓漢式?因為餓漢式類一載入就建立物件,這樣影響效能,我們更希望在使用物件的時候才去載入它
* 用一句話描述一下靜態內部類實現單例模式的做法
答:在類的內部
1. 宣告乙個靜態的內部類,該內部類使用餓漢式方式來獲取例項物件。
2. 宣告乙個靜態方法來返回這個例項物件
* 併發類容器
* hashtable vector --> collections.synchronizedmap() --> concurrentedhashmap
* 併發類容器
hashmap --> concurrenthashmap
treemap --> concurrentskiplistmap
vector --> copyonwritearraylist
--> copyonwritearrayset
* concurrenthashmap內部實現
* 原理:
使用鎖分段機制(16段segment),每個段其實就是乙個小的hashtable,各自都由自己的鎖,只要多個修改操作發生在不同的段上,它們就可以併發進行。把乙個整體分成16個段(segment),也就是最高支援16個執行緒的併發修改操作。並且**中大多共享變數,使用volatile關鍵字宣告,目的是第一時間獲取修改的內容,效能非常好
* 設計思想:
減小鎖的粒度
* copyonwrite(cow)
* 概念:
是一種程式設計中的優化策略
copyonwrite即寫時複製的容器。通俗的理解是當我們向乙個容器新增元素的時候,不直接往當前容器新增,而是先將當前容器進行copy,複製出乙個新的容器,然後往新的容器裡新增元素,新增元素後,再將原容器的引用指向新的容器。
這樣做的好處是我們可以對copyonwrite容器進行併發的讀,而不需要加鎖,因為當前容器不會新增任何元素。
所以copyonwrite體現了一種讀寫分離的思想。
* 設計思想:
讀寫分離,讀和寫在不同的容器
* 適合應用:
由設計概念可知,它適合讀多寫少的情況下比較適合
* 併發queue
* concurrentlinkedqueue -- 高效能無界無阻塞佇列 -- 無鎖
* 適合在高併發場景下的佇列,通過無鎖的方式,實現了高併發狀態下的高效能。
* 通常concurrentlinkedqueue效能好於blockingqueue
* 它是乙個基於鏈結節點的無界線程安全佇列。該佇列的元素遵循先進先出的原則。頭是最先加入的,尾是最近加入的,該佇列不允許null元素
* 重要方法:
add()和offer(): 都是新增元素,在本容器中,兩個方法無差別
poll()和peek(): 都是取頭節點元素,區別:poll會刪除元素,peek不會
* arrayblockingqueue -- 沒有用到鎖
* 基於陣列的阻塞佇列實現
* 在arrayblockingqueue內部維護了乙個定長的陣列,以便快取佇列的資料物件,其內部沒實現讀寫分離,也就意味著生產和消費不能完全並行,長度是需要定義的,可以指定先進先出還是先進後出,也叫有界佇列
* linkedblockingqueue -- 讀寫分離鎖
* 基於鍊錶的阻塞佇列
* 同arrayblockingqueue類似,其內部也維持著乙個資料緩衝佇列(該佇列由乙個鍊錶構成),linkblockingqueue之所以能高效地處理併發資料,是因為其內部實現採用了分離鎖(讀與寫分離兩個鎖),從而實現生產者消費者的操作完全並行,它是乙個無界佇列
* 備註:如果初始化的時候指定了長度,它也會變成有界佇列
* priorityblockingqueue -- 公平鎖
* 基於優先順序的阻塞佇列(優先順序的判斷通過建構函式傳入的compator物件指定,也就是傳入佇列的物件必須實現comparable介面)
* priorityblockingqueue內部控制線程同步的鎖是公平鎖,它是乙個無界佇列
* delayqueue
* 帶有延遲時間的queue,其中的元素只有當其指定的延遲時間到了,才能夠從佇列中獲取到該元素。
* delayquue元素必須實現delayed介面,delayqueue是乙個無界佇列
* 應用場景:
快取超過時間對資料進行移除、任務超時處理、空閒鏈結的關閉
* synchronousqueue
* 一種沒有緩衝的佇列,生產者產生的資料直接會被消費者獲取並消費
* future設計模式
* 原理
* 當程式請求某個資料資源的時候,伺服器返回該資料資源物件的乙個類似**的furture物件作為請求結果,程式就無需等待獲取資料,可以繼續執行。
* 伺服器返回furturedata後,自己偷偷去請求獲得真實資料,並將真實的資料設定進futruedata中,這時候程式如果要請求結果,就可以通過furturedata獲得真實資料
* 例項:檢視練習
* 實現:
* master-worker設計模式
* 核心思想:
* 系統由兩類程序協作工作,master程序和worker程序。
* master負責接收和分配任務,worker負責處理子任務
* 當各個worker子程序處理完成後,會將結果返回給master,由master歸納和總結
* 其好處是能將大任務分解成若干個小任務,並行執行,從而提高系統的吞吐量
執行緒池:
減少來回切換執行緒池
復用減少建立執行緒時的消耗
併發基礎 Linux多執行緒程式設計
linux 下的多執行緒程式設計使用pthread posix thread 函式庫,使用時包含標頭檔案pthread.h,鏈結共享庫libpthread.so。這裡順便說一下gcc鏈結共享庫的方式 l用來指定共享庫所在目錄,系統庫目錄不用指定。l用來指定要鏈結的共享庫,只需要指定庫的名字就行了,如...
執行緒併發基礎
多核心 chip mutilprocessors 單晶元多處理器 cmp 多執行緒 simultaneous multithreading smt 如果在時間片結束時,程序還在執行,則cpu將被剝奪並分配給另乙個程序。如果程序在時間片結束之前阻塞或結束,則cpu當即進行切換。排程程式做的是維護一張就...
執行緒池及併發程式設計基礎總結
executorservice threadpool executors.newfixedthreadpool 3 建立可以容納3個執行緒的執行緒池executorservice threadpool executors.newcachedthreadpool 執行緒池的大小會根據執行的任務數動態分...