CopyOnWriteArrayList真的完全線程安全嗎

CopyOnWriteArrayList是開發(fā)過程中常用的一種并發(fā)容器,多用于讀多寫少的并發(fā)場景。但是CopyOnWriteArrayList真的能做到完全的線程安全嗎?
答案是并不能。

CopyOnWriteArrayList原理

我們可以看出當我們向容器添加或刪除元素的時候虎敦,不直接往當前容器添加刪除,而是先將當前容器進行Copy政敢,復(fù)制出一個新的容器其徙,然后新的容器里添加刪除元素,添加刪除完元素之后堕仔,再將原容器的引用指向新的容器擂橘,整個過程加鎖,保證了寫的線程安全摩骨。

    public boolean add(E e) {
        synchronized (lock) {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        }
    }

    public E remove(int index) {
        synchronized (lock) {
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = get(elements, index);
            int numMoved = len - index - 1;
            if (numMoved == 0)
                setArray(Arrays.copyOf(elements, len - 1));
            else {
                Object[] newElements = new Object[len - 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index + 1, newElements, index,
                                 numMoved);
                setArray(newElements);
            }
            return oldValue;
        }
    }

而因為寫操作的時候不會對當前容器做任何處理,所以我們可以對容器進行并發(fā)的讀朗若,而不需要加鎖恼五,也就是讀寫分離。

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

一般來講我們使用時哭懈,會用一個線程向容器中添加元素灾馒,一個線程來讀取元素,而讀取的操作往往更加頻繁遣总。寫操作加鎖保證了線程安全睬罗,讀寫分離保證了讀操作的效率,簡直完美旭斥。

數(shù)組越界

但想象一下如果這時候有第三個線程進行刪除元素操作容达,讀線程去讀取容器中最后一個元素,讀之前的時候容器大小為i垂券,當去讀的時候刪除線程突然刪除了一個元素花盐,這個時候容器大小變?yōu)榱薸-1,讀線程仍然去讀取第i個元素,這時候就會發(fā)生數(shù)組越界算芯。

測試一下柒昏,首先向CopyOnWriteArrayList里面塞10000個測試數(shù)據(jù),啟動兩個線程熙揍,一個不斷的刪除元素职祷,一個不斷的讀取容器中最后一個數(shù)據(jù)。

    public void test(){
        for(int i = 0; i<10000; i++){
            list.add("string" + i);
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    if (list.size() > 0) {
                        String content = list.get(list.size() - 1);
                    }else {
                        break;
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    if(list.size() <= 0){
                        break;
                    }
                    list.remove(0);
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

運行届囚,可以看出刪除到第7個元素的時候就發(fā)生了數(shù)組越界


error.png

從上可以看出CopyOnWriteArrayList并不是完全意義上的線程安全堪旧,如果涉及到remove操作,一定要謹慎處理奖亚。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末淳梦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子昔字,更是在濱河造成了極大的恐慌爆袍,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件作郭,死亡現(xiàn)場離奇詭異陨囊,居然都是意外死亡,警方通過查閱死者的電腦和手機夹攒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門蜘醋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人咏尝,你說我怎么就攤上這事压语。” “怎么了编检?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵胎食,是天一觀的道長。 經(jīng)常有香客問我允懂,道長厕怜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任蕾总,我火速辦了婚禮粥航,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘生百。我一直安慰自己递雀,他們只是感情好,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布置侍。 她就那樣靜靜地躺著映之,像睡著了一般拦焚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杠输,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天赎败,我揣著相機與錄音,去河邊找鬼蠢甲。 笑死僵刮,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的鹦牛。 我是一名探鬼主播搞糕,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼曼追!你這毒婦竟也來了窍仰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤礼殊,失蹤者是張志新(化名)和其女友劉穎驹吮,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晶伦,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡碟狞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了婚陪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片族沃。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖泌参,靈堂內(nèi)的尸體忽然破棺而出脆淹,到底是詐尸還是另有隱情,我是刑警寧澤及舍,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布未辆,位于F島的核電站,受9級特大地震影響锯玛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜兼蜈,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一攘残、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧为狸,春花似錦歼郭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牍蜂。三九已至,卻和暖如春泰涂,著一層夾襖步出監(jiān)牢的瞬間鲫竞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工逼蒙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留从绘,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓是牢,卻偏偏與公主長得像僵井,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子驳棱,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容