中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

什么是CopyOnwrite

發布時間:2021-10-28 18:02:28 來源:億速云 閱讀:152 作者:iii 欄目:web開發

本篇內容介紹了“什么是CopyOnwrite”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

概念

CopyOnWrite 只是看字面意思就能看出來,就是在寫入時復制,說得輕巧,寫入時復制,具體是怎么實現的呢?

先來說說思想,具體怎么實現等下分析

CopyOnWrite  的思想就是:當向一個容器中添加元素的時候,不是直接在當前這個容器里面添加的,而是復制出來一個新的容器,在新的容器里面添加元素,添加完畢之后再將原容器的引用指向新的容器,這樣就實現了寫入時復制

你還記得在提到數據庫的時候,一般都會說主從復制,讀寫分離嗎?CopyOnWrite 的設計思想是不是和經常說的主從復制,讀寫分離如出一撤?

優缺點

了解概念之后,對它的優缺點應該就比較好理解了

優點就是,讀和寫可以并行執行,因為讀的是原來的容器,寫的是新的容器,它們之間互不影響,所以讀和寫是可以并行執行的,在某些高并發場景下,可以提高程序的響應時間

但是呢,你也看到了, CopyOnWrite  是在寫入的時候,復制了一個新的容器出來,所以要考慮它的內存開銷問題,又回到了在學算法時一直強調的一個思想:拿空間換時間

需要注意一下,它只保證數據的最終一致性。因為在讀的時候,讀取的內容是原容器里面的內容,新添加的內容是讀取不到的

基于它的優缺點應該就可以得出一個結論:CopyOnWrite 適用于寫操作非常少的場景,而且還能夠容忍讀寫的暫時不一致  如果你的應用場景不適合,那還是考慮使用別的方法來實現吧

還有一點需要注意的是:在寫入時,它會復制一個新的容器,所以如果有寫入需求的話,最好可以批量寫入,因為每次寫入的時候,容器都會進行復制,如果能夠減少寫入的次數,就可以減少容器的復制次數

在 JUC 包下,實現 CopyOnWrite 思想的就是 CopyOnWriteArrayList & CopyOnWriteArraySet  這兩個方法,本篇文章側重于講清楚 CopyOnWriteArrayList

CopyOnWriteArrayList

在 CopyOnWriteArrayList 中,需要注意的是 add 方法:

public boolean add(E e) {         final ReentrantLock lock = this.lock;         // 在寫入的時候,需要加鎖,如果不加鎖的話,在多線程場景下可能會被 copy 出 n 個副本出來         // 加鎖之后,就能保證在進行寫時,只有一個線程在操作         lock.lock();         try {             Object[] elements = getArray();             int len = elements.length;             // 復制原來的數組             Object[] newElements = Arrays.copyOf(elements, len + 1);             // 將要添加的元素添加到新數組中             newElements[len] = e;             // 將對原數組的引用指向新的數組             setArray(newElements);             return true;         } finally {             lock.unlock();         }     }

在寫的時候需要加鎖,但是在讀取的時候不需要添加

因為讀取的是原數組的元素,對新數組沒有什么影響,加了鎖反而會增加性能開銷

public E get(int index) {  return get(getArray(), index); }

舉個例子:

@Slf4j public class ArrayListExample {      // 請求總數     public static int clientTotal = 5000;      // 同時并發執行的線程數     public static int threadTotal = 200;      private static List<Integer> list = new ArrayList<>();      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);     } }

上面是客戶端請求 5000 次,有 200 個線程在同時請求,我使用的是 ArrayList 實現,咱們看下打印結果:

如果是線程安全的話,那么最后的結果應該是 5000 才對,多運行幾次你會發現,每次程序的執行結果都是不一樣的

如果是 CopyOnWriteArrayList 呢?

@Slf4j 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("excepiton",e);                 }                 countDownLatch.countDown();             });         }         countDownLatch.await();         executorService.shutdown();         log.info("size:{}",list.size());     }     private static void update(int i){         list.add(i);     } }

多運行幾次,結果都是一樣的:

由此可見, CopyOnWriteArrayList 是線程安全的

“什么是CopyOnwrite”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節
推薦閱讀:
  1. 什么是PHP
  2. 什么是python

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宁晋县| 长治县| 临澧县| 英超| 滦平县| 清河县| 泾阳县| 云阳县| 昌邑市| 福清市| 枣强县| 梁山县| 东乌| 桐乡市| 南丹县| 盐山县| 固镇县| 绥阳县| 东乡族自治县| 资溪县| 阳谷县| 美姑县| 西乡县| 华阴市| 安宁市| 贺兰县| 民乐县| 察雅县| 松潘县| 信丰县| 上犹县| 兴和县| 东乌| 株洲市| 伊春市| 四子王旗| 行唐县| 湟源县| 汤阴县| 辛集市| 临沂市|