【轉】Java多執行緒-同步集合和併發集合
同步集合可以簡單地理解為通過synchronized來實現同步的集合。如果有多個執行緒呼叫同步集合的方法,它們將會序列執行。
arrayList和vector、stack
- Vector是執行緒安全的,原始碼中有很多的synchronized可以看出,而ArrayList不是。導致Vector效率無法和ArrayList相比
- ArrayList和Vector都採用線性連續儲存空間,當儲存空間不足的時候,ArrayList預設增加為原來的50%,Vector預設增加為原來的一倍
- Vector可以設定capacityIncrement,而ArrayList不可以,從字面理解就是capacity容量,Increment增加,容量增長的引數
- Stack是繼承於Vector,基於動態陣列實現的一個執行緒安全的棧
- arrayList、vector、Stack的共性特點:隨機訪問速度快,插入和移除效能較差(這是陣列的特點,三者的底層均為陣列實現)
HashMap和Hashtable
- HashMap是非synchronized的,而Hashtable是synchronized的。這說明Hashtable是執行緒安全的,而且多個執行緒可以共享一個Hashtable
- 由於Hashtable是執行緒安全的,也是synchronized的,所以在單執行緒環境下比HashMap要慢
- HashMap可以存在null的鍵值(key)和值(value), 但是Hashtable是不可以的
Collections
Collections是為集合提供各種方便操作的工具類,通過它,可以實現集合排序、查詢、替換、同步控制、設定不可變集合
Collections.synchronizedCollection(Collection<T>t)
Collections.synchronizedList(List<T>list)
Collections.synchronizedMap(Map<K, V>map)
Collections.synchronizedSet(Set<T> t)
上面幾個方法是Collections工具類將集合變為同步集合,從而解決集合的執行緒安全問題.
同步集合在單執行緒的環境下能夠保證執行緒安全,但是通過synchronized同步方法將訪問操作序列化,導致併發環境下效率低下。而且同步集合在多執行緒環境下的複合操作(迭代、條件運算如沒有則新增等)是非執行緒安全,需要客戶端程式碼來實現加鎖。
併發集合是jdk5.0重要的特性,增加了併發包java.util.concurrent.*。Java記憶體模型、volatile變數及AbstractQueuedSynchronizer(簡稱AQS同步器),是併發包眾多實現的基礎。
常見的併發集合:
ConcurrentHashMap:
執行緒安全的HashMap的實現CopyOnWriteArrayList:
執行緒安全且在讀操作時無鎖的ArrayListCopyOnWriteArraySet:
基於CopyOnWriteArrayList,不新增重複元素ArrayBlockingQueue:
基於陣列、先進先出、執行緒安全,可實現指定時間的阻塞讀寫,並且容量可以限制LinkedBlockingQueue:
基於連結串列實現,讀寫各用一把鎖,在高併發讀寫操作都多的情況下,效能優於ArrayBlockingQueue
CopyOnWrite集合即寫時複製的集合
通俗的理解是當我們往一個集合新增元素的時候,不直接往當前集合新增,而是先將當前集合進行Copy,複製出一個新的集合,然後新的集合裡新增元素,新增完元素之後,再將原集合的引用指向新的集合。這樣做的好處是我們可以對CopyOnWrite集合進行併發的讀,而不需要加鎖,因為當前集合不會新增任何元素。所以CopyOnWrite集合也是一種讀寫分離的思想,讀和寫不同的集合。
CopyOnWrite的應用場景
CopyOnWrite併發容器用於讀多寫少的併發場景。比如白名單,黑名單,商品類目的訪問和更新場景,假如我們有一個搜尋網站,使用者在這個網站的搜尋框中,輸入關鍵字搜尋內容,但是某些關鍵字不允許被搜尋。這些不能被搜尋的關鍵字會被放在一個黑名單當中,黑名單每天晚上更新一次。當用戶搜尋時,會檢查當前關鍵字在不在黑名單當中,如果在,則提示不能搜尋。
示例程式碼
package com.ifeve.book;
import java.util.Map;
import com.ifeve.book.forkjoin.CopyOnWriteMap;
/**
* 黑名單服務
*
* @author fangtengfei
*
*/
public class BlackListServiceImpl {
private static CopyOnWriteMap<String, Boolean> blackListMap = new CopyOnWriteMap<String, Boolean>(
1000);
public static boolean isBlackList(String id) {
return blackListMap.get(id) == null ? false : true;
}
public static void addBlackList(String id) {
blackListMap.put(id, Boolean.TRUE);
}
/**
* 批量新增黑名單
*
* @param ids
*/
public static void addBlackList(Map<String,Boolean> ids) {
blackListMap.putAll(ids);
}
}
注意兩點:
- 減少擴容開銷。根據實際需要,初始化CopyOnWriteMap的大小,避免寫時CopyOnWriteMap擴容的開銷。
- 使用批量新增。因為每次新增,容器每次都會進行復制,所以減少新增次數,可以減少容器的複製次數。如使用上面程式碼裡的addBlackList方法。
CopyOnWrite的缺點
記憶體佔用問題
因為CopyOnWrite的寫時複製機制,所以在進行寫操作的時候,記憶體裡會同時駐紮兩個物件的記憶體,舊的物件和新寫入的物件(注意:在複製的時候只是複製容器裡的引用,只是在寫的時候會建立新物件新增到新容器裡,而舊容器的物件還在使用,所以有兩份物件記憶體)。如果這些物件佔用的記憶體比較大,比如說200M左右,那麼再寫入100M資料進去,記憶體就會佔用300M,那麼這個時候很有可能造成頻繁的Yong GC和Full GC。之前我們系統中使用了一個服務由於每晚使用CopyOnWrite機制更新大物件,造成了每晚15秒的Full GC,應用響應時間也隨之變長。
針對記憶體佔用問題,可以通過壓縮容器中的元素的方法來減少大物件的記憶體消耗,比如,如果元素全是10進位制的數字,可以考慮把它壓縮成36進位制或64進位制。或者不使用CopyOnWrite容器,而使用其他的併發容器,如ConcurrentHashMap。
資料一致性問題
CopyOnWrite容器只能保證資料的最終一致性,不能保證資料的實時一致性。所以如果你希望寫入的的資料,馬上能讀到,請不要使用CopyOnWrite容器。
相關推薦
【轉】Java多執行緒-同步集合和併發集合
同步集合可以簡單地理解為通過synchronized來實現同步的集合。如果有多個執行緒呼叫同步集合的方法,它們將會序列執行。 arrayList和vector、stack Vector是執行緒安全的,原始碼中有很多的synchronized可以看出,而
【轉】Java多執行緒-CyclicBarrier 柵欄
CyclicBarrier 類介紹 CyclicBarrier是一個同步工具類,它允許一組執行緒在到達某個柵欄點(common barrier point)互相等待,發生阻塞,直到最後一個執行緒到達柵欄點,柵欄才會開啟,處於阻塞狀態的執行緒恢復繼續執行.它
java 多執行緒 同步 觀察者 併發集合的一個例子
//第一版 package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type; import org.springframework.boot.SpringApplication; import org.springfram
Java多執行緒 阻塞佇列和併發集合
本章主要探討在多執行緒程式中與集合相關的內容。在多執行緒程式中,如果使用普通集合往往會造成資料錯誤,甚至造成程式崩潰。Java為多執行緒專門提供了特有的執行緒安全的集合類,通過下面的學習,您需要掌握這些集合的特點是什麼,底層實現如何、在何時使用等問題。 3.1Blockin
【 專欄 】- Java 多執行緒程式設計
Java 多執行緒程式設計 Java多執行緒程式設計,是併發程式設計的一種(另一種重要的併發程式設計是多程序程式設計)。我們寫java程式一般是執行在同一個程序中的,所以可以簡單的認為:併發程式設計 = 多執行緒程式設計,讓寫作業
【VS2010】C++多執行緒同步與互斥簡單運用
繼以往的想法,寫這點文字,貼上點程式碼,是為了增加自己的記憶,也希望能幫助到需要幫助的人。 1. 互斥量,Mutex #include <Windows.h> #include <iostream> usingnamespace
【自用】java多執行緒程式設計學習筆記(程式碼片段來源於網路)
執行緒的基本概念 執行緒是在邏輯上等同於作業系統中說的程序,是程序的細分。比如我們使用同一個軟體同時對電腦進行體檢和防毒的時候,我們就是開啟了那個軟體的程序的兩個執行緒,在邏輯上這兩個執行緒是同時被cpu執行的。 執行緒的生命週期 執行緒的生命週期分為建立,就緒,執行,
【原】對多執行緒中Wait和Join的理解
對於,wait方法的解釋,有時候覺得很矛盾。呼叫某個物件的wait時,需要獲得該物件的鎖,在執行的時候又需要釋放該物件的所有鎖。這是問題一。 另外,在看Join的原始碼,會發現它利用了Wait來實現,但是它的實現原理是怎樣的呢? 這是問題二。 看下原始碼的英文描述:
【Dr.Chen的系列問題】Java多執行緒的實現操作
一、什麼是多執行緒? 多執行緒(英語:multithreading),是指從軟體或者硬體上實現多個執行緒併發執行的技術。具有多執行緒能力的計算機因有硬體支援而能夠在同一時間執行多於一個執行緒,進而提升整體處理效能。具有這種能力的系統包括對稱多處理機、多核心處理器以及晶片級多
【本人禿頂程式設計師】JAVA多執行緒之執行緒間的通訊方式
←←←←←←←←←←←← 我都禿頂了,還不點關注! 一,介紹 本總結我對於JAVA多執行緒中執行緒之間的通訊方式的理解,主要以程式碼結合文字的方式來討論執行緒間的通訊,故摘抄了書中的一些示例程式碼。 二,執行緒間的通訊方式 ①同步 這裡講的同步是指多個執行緒通過synchro
【面試總結】java多執行緒
4.1 ThreadLocal為什麼會產生記憶體洩露(建議結合原始碼學習) https://blog.csdn.net/puppylpg/article/details/8043
【Java】Java多執行緒實現的聊天客戶端和伺服器
主要涉及知識 ·Java中GUI程式的編寫,包括事件監聽機制。 ·Java的網路通訊程式設計,ServerSocket,Socket類的使用。 ·Java中多執行緒的程式設計,Thread類,Runnable介面的使用。 原始碼 客戶端 package project1
【Java程式設計】Java多執行緒的實現
多執行緒 程式:是一個指令的集合。 程序:正在執行中的程式,是一個靜態的概念。 執行緒:是程序中的一個單一的連續控制流程,執行緒又本稱為輕量級程序。 一個程序可擁有多個並行的執行緒,一個程序中的執行緒共享相同的記憶體單元,記憶體地址空間,可以訪問相同的變數和物件,而且他們從
Java 多執行緒同步的五種方法 [轉]
程式碼很簡單,我就不解釋了,看看執行結果怎樣呢?截取了其中的一部分,是不是很亂,有寫看不懂。 餘額不足 賬戶餘額:0 餘額不足 賬戶餘額:100 1441790503354存進:100 賬戶餘額:100 1441790504354存進:100 賬戶餘額:100 144179050
【多執行緒】java多執行緒全域性變數共享問題
【自己的總結】 package dc.stock; import dc.stock.policies.StockP1_1_notComIn; /** * 執行策略的【統一的】方法入口; * 之所以單獨列出來,是為了多執行緒的使用; */ public class
【對線面試官】Java多執行緒基礎
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c3ad3d76a4d04a9680160f319c889287~tplv-k3u1fbpfcp-zoom-1.image) ![](https://p3-juejin.byteimg.com/tos
java 多執行緒同步
執行緒屬性: 1.執行緒優先順序, 優先順序高度依賴於系統,不要讓程式的正確性依賴於優先順序。預設情況子執行緒會繼承父執行緒的優先順序。 2.守護執行緒, 唯一用途是為其他執行緒提供服務,當只剩
Java多執行緒-44-靜態和非靜態方法同步鎖物件是什麼
前面一篇,我們知道了synchronized關鍵字擴起來範圍的程式碼塊就可以實現同步,其實,在Java中,只需要在方法上加上synchronized關鍵字即可,就像加上static一樣。本篇來看看加上synchronized關鍵字修飾的非靜態和靜態方法的同步鎖物件是什麼。 1.非靜態同步鎖物
【轉】Leader-Follower執行緒模型
上圖就是L/F多執行緒模型的狀態變遷圖,共6個關鍵點: (1)執行緒有3種狀態:領導leading,處理processing,追隨following (2)假設共N個執行緒,其中只有1個leading執行緒(等待任務),x個processing執行緒(處理),餘下有N-1-x個following執行緒
【轉】在子執行緒中new Handler報錯--Can't create handler inside thread that has not called Looper.prepare()
在子執行緒中new一個Handler為什麼會報以下錯誤? java.lang.RuntimeException: Can't create handler inside thread that has not ca