java併發面試常識之copyonwrite

daqianmen發表於2021-09-09

        今天在網上看到一個問題,問除了加鎖之外有沒有其他方法來保證執行緒安全。樓下很多回答copyonwrite機制。這個問題回答有很多,但是copyonwrite的回答有點誤導人。

copyonwrite機制

        和單詞描述的一樣,他的實現就是寫時複製, 在往集合中新增資料的時候,先複製儲存的陣列,然後新增元素到複製好的陣列中,然後用現在的陣列去替換成員變數的陣列(就是get等讀取操作讀取的陣列)。這個機制和讀寫鎖是一樣的,但是比讀寫鎖有改進的地方,那就是讀取的時候可以寫入的 ,這樣省去了讀寫之間的競爭,看了這個過程,你也發現了問題,同時寫入的時候怎麼辦呢,當然果斷還是加鎖。

java中的copyonwrite

        java中提供了兩個利用這個機制實現的執行緒安全集合。copyonwritearraylist,copyonwritearrayset。看名字就大概猜到他們之間的關係,copyonwritearrayset的底層實現是copyonwritearraylist。我們接下來看看java的實現。

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

        get的方法就是普通集合的get沒有什麼特殊的地方,但是成員變數的宣告還是有講究的,是個用volatile宣告的陣列,這樣就保證了讀取的那一刻讀取的是最新的資料。

private transient volatile Object[] array;

     接下來重點就是add方法了。下面的程式碼可以明顯看出是明顯需要reentrantlock加鎖的,接下來就是複製資料和新增資料的過程,在setArray的過程中,把新的陣列賦值給成員變數array(這裡是引用的指向,java保證賦值的過程是一個原子操作)。

  public void add(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            if (index > len || index 

         關於迭代,他採取的是獲取傳遞給迭代器的陣列值進行迭代,中間就算加入新的值也迭代不到。在建構函式中就直接賦值給final的成員變數。

        private final Object[] snapshot;

        private COWIterator(Object[] elements, int initialCursor) {
            cursor = initialCursor;
            snapshot = elements;
        }
適用場景

        copyonwrite的機制雖然是執行緒安全的,但是在add操作的時候不停的複製是一件很費時的操作,所以使用到這個集合的時候儘量不要出現頻繁的新增操作,而且在迭代的時候資料也是不及時的,資料量少還好說,資料太多的時候,實時性可能就差距很大了。在多讀取,少新增的時候,他的效果還是不錯的(資料量大無所謂,只要你不新增,他都是好用的)。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1727/viewspace-2800350/,如需轉載,請註明出處,否則將追究法律責任。

相關文章