什么是CopyOnwrite

本篇內(nèi)容介紹了“什么是CopyOnwrite”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

10年積累的網(wǎng)站制作、做網(wǎng)站經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有鎮(zhèn)寧免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

概念

CopyOnWrite 只是看字面意思就能看出來,就是在寫入時(shí)復(fù)制,說得輕巧,寫入時(shí)復(fù)制,具體是怎么實(shí)現(xiàn)的呢?

先來說說思想,具體怎么實(shí)現(xiàn)等下分析

CopyOnWrite  的思想就是:當(dāng)向一個(gè)容器中添加元素的時(shí)候,不是直接在當(dāng)前這個(gè)容器里面添加的,而是復(fù)制出來一個(gè)新的容器,在新的容器里面添加元素,添加完畢之后再將原容器的引用指向新的容器,這樣就實(shí)現(xiàn)了寫入時(shí)復(fù)制

你還記得在提到數(shù)據(jù)庫的時(shí)候,一般都會說主從復(fù)制,讀寫分離嗎?CopyOnWrite 的設(shè)計(jì)思想是不是和經(jīng)常說的主從復(fù)制,讀寫分離如出一撤?

優(yōu)缺點(diǎn)

了解概念之后,對它的優(yōu)缺點(diǎn)應(yīng)該就比較好理解了

優(yōu)點(diǎn)就是,讀和寫可以并行執(zhí)行,因?yàn)樽x的是原來的容器,寫的是新的容器,它們之間互不影響,所以讀和寫是可以并行執(zhí)行的,在某些高并發(fā)場景下,可以提高程序的響應(yīng)時(shí)間

但是呢,你也看到了, CopyOnWrite  是在寫入的時(shí)候,復(fù)制了一個(gè)新的容器出來,所以要考慮它的內(nèi)存開銷問題,又回到了在學(xué)算法時(shí)一直強(qiáng)調(diào)的一個(gè)思想:拿空間換時(shí)間

需要注意一下,它只保證數(shù)據(jù)的最終一致性。因?yàn)樵谧x的時(shí)候,讀取的內(nèi)容是原容器里面的內(nèi)容,新添加的內(nèi)容是讀取不到的

基于它的優(yōu)缺點(diǎn)應(yīng)該就可以得出一個(gè)結(jié)論:CopyOnWrite 適用于寫操作非常少的場景,而且還能夠容忍讀寫的暫時(shí)不一致  如果你的應(yīng)用場景不適合,那還是考慮使用別的方法來實(shí)現(xiàn)吧

還有一點(diǎn)需要注意的是:在寫入時(shí),它會復(fù)制一個(gè)新的容器,所以如果有寫入需求的話,最好可以批量寫入,因?yàn)槊看螌懭氲臅r(shí)候,容器都會進(jìn)行復(fù)制,如果能夠減少寫入的次數(shù),就可以減少容器的復(fù)制次數(shù)

在 JUC 包下,實(shí)現(xiàn) CopyOnWrite 思想的就是 CopyOnWriteArrayList & CopyOnWriteArraySet  這兩個(gè)方法,本篇文章側(cè)重于講清楚 CopyOnWriteArrayList

CopyOnWriteArrayList

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

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

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

因?yàn)樽x取的是原數(shù)組的元素,對新數(shù)組沒有什么影響,加了鎖反而會增加性能開銷

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

舉個(gè)例子:

@Slf4j public class ArrayListExample {      // 請求總數(shù)     public static int clientTotal = 5000;      // 同時(shí)并發(fā)執(zhí)行的線程數(shù)     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 個(gè)線程在同時(shí)請求,我使用的是 ArrayList 實(shí)現(xiàn),咱們看下打印結(jié)果:

如果是線程安全的話,那么最后的結(jié)果應(yīng)該是 5000 才對,多運(yùn)行幾次你會發(fā)現(xiàn),每次程序的執(zhí)行結(jié)果都是不一樣的

如果是 CopyOnWriteArrayList 呢?

@Slf4j public class CopyOnWriteArrayListExample {      // 請求總數(shù)     public static int clientTotal = 5000;      // 同時(shí)并發(fā)執(zhí)行的線程數(shù)     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);     } }

多運(yùn)行幾次,結(jié)果都是一樣的:

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

“什么是CopyOnwrite”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

名稱欄目:什么是CopyOnwrite
當(dāng)前URL:http://bm7419.com/article8/ipooop.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)、動態(tài)網(wǎng)站、網(wǎng)站維護(hù)域名注冊、網(wǎng)站導(dǎo)航、網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)