概念 : 簡單的講就是寫操做時賦值,當有新元素添加到CopyOnWriteArrayList時,它先從原有的數組裏邊Copy一份出來而後在新的數組上作些操做,操做完成之後在將引用指向新的數組;CopyOnWriteArrayList全部的操做都是在鎖的保護下進行的,這樣作的目的主要是爲了在多線程併發作add操做的時候複製出多個副本出來致使數據混亂;java
① 因爲是copy的操做因此比較消耗內存,若是元素的內容較多的時候可能會觸發GC,數組
② 不能用於實時讀的場景,它比較適合讀多寫少的場景;安全
① 讀寫分離;多線程
② 最終一致性;併發
③ 另外開闢空間解決併發衝突;優化
// CopyOnWriteArrayList @Slf4j @ThreadSafe public class CopyOnWriteArrayListExample { // 請求總數 public static int clientTotal = 5000; // 同時併發執行的線程數 public static int threadTotal = 200; private static List<Integer> list = new CopyOnWriteArrayList<>(); public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(() -> { try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}", list.size()); } private static void update(int i) { list.add(i); } }
概念 :ui
CopyOnWriteArraySet它是線程安全,底層實現是使用CopyOnWriteArrayList,它的不少特性都與CopyOnWriteArrayList類似包括適用場景;spa
ConcurrentSkipListSet是jdk6新增的類,支持天然排序,能夠在構造的時候本身定義比較器,它是基於Map集合的,在多線程環境下ConcurrentSkipListSet它裏邊的remote add 等方法都是線程安全的,可是對於批量操做並不能保證以原子方式進行操做,在批量操做的時候只能保證每一次的操做是原子性的;ConcurrentSkipListSet在使用批量操做的時候可能須要手動處理一下;線程
// CopyOnWriteArraySet @Slf4j @ThreadSafe public class CopyOnWriteArraySetExample { // 請求總數 public static int clientTotal = 5000; // 同時併發執行的線程數 public static int threadTotal = 200; private static Set<Integer> set = new CopyOnWriteArraySet<>(); public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(() -> { try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}", set.size()); } private static void update(int i) { set.add(i); } }
// ConcurrentSkipListSet @Slf4j @ThreadSafe public class ConcurrentSkipListSetExample { // 請求總數 public static int clientTotal = 5000; // 同時併發執行的線程數 public static int threadTotal = 200; private static Set<Integer> set = new ConcurrentSkipListSet<>(); public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(() -> { try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}", set.size()); } private static void update(int i) { set.add(i); } }
概念 :code
ConcurrentHashMap是HashMap線程安全的版本,ConcurrentHashMap不容許空值,在實際的應用中除了少數的插入操做和刪除操做外,絕大多數操做都是讀取操做,並且讀操做大多數都是成功的,基於這個前提ConcurrentHashMap針對讀操做多了特別多的優化,具備特別高的併發性;
ConcurrentSkipListMap是TreeMap線程安全的版本,ConcurrentSkipListMap底層是使用SkipList這種跳錶的結構實現的;
// ConcurrentHashMap @Slf4j @ThreadSafe public class ConcurrentHashMapExample { // 請求總數 public static int clientTotal = 5000; // 同時併發執行的線程數 public static int threadTotal = 200; private static Map<Integer, Integer> map = new ConcurrentHashMap<>(); public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(() -> { try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}", map.size()); } private static void update(int i) { map.put(i, i); } }
// ConcurrentSkipListMap @Slf4j @ThreadSafe public class ConcurrentSkipListMapExample { // 請求總數 public static int clientTotal = 5000; // 同時併發執行的線程數 public static int threadTotal = 200; private static Map<Integer, Integer> map = new ConcurrentSkipListMap<>(); public static void main(String[] args) throws Exception { ExecutorService executorService = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(threadTotal); final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(() -> { try { semaphore.acquire(); update(count); semaphore.release(); } catch (Exception e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}", map.size()); } private static void update(int i) { map.put(i, i); } }
1 線程限制 : 一個被線程限制的對象,由線程獨佔,而且只能被佔有它的線程修改;
2 共享只讀 : 一個共享只讀的對象,在沒有額外同步的狀況下,能夠被多個線程併發訪問,可是任何線程都不能修改它;
3 線程安全對象 : 一個線程安全的對象或者容器,在內部經過同步機制來保證線程安全,因此其餘線程無需額外的同步就能夠經過公共接口隨意訪問它;
4 被守護對象 : 被守護對象只能經過獲取特定的鎖來訪問;