简体   繁体   中英

Why the results are strange when using CopyOnWriteArrayList?

when I use multithreads with CopyOnWriteArrayList, the output result sometimes is not the target. The code is:

public class CopyOnWriteArrayListTest {

    public static void main(String[] args) throws InterruptedException {
        while(true){

        CopyOnWriteArrayList<String> ll = new CopyOnWriteArrayList<String>(new String[10]);

        CountDownLatch latch = new CountDownLatch(2);
        ThreadDemo t1 = new ThreadDemo(0, ll, latch);
        ThreadDemo t2 = new ThreadDemo(1, ll, latch);

        t1.start();
        t2.start();

        latch.await();
        System.out.println(ll);
        }
    }
}

public class ThreadDemo extends Thread implements Runnable {
    private int code;
    private List<String> list;
    private CountDownLatch latch;
    public ThreadDemo(int i, List<String> l, CountDownLatch latch){
        code = i;
        list = l;
        this.latch = latch;
    }

    @Override
    public void run() {
        writeList(list);
    }

    private synchronized void writeList(List<String> l){
        l.add(code, String.valueOf(code));
        latch.countDown();
    }

}

And the outputs are [0, 1, null, null, null, null, null, null, null, null, null, null] or [0, null, 1, null, null, null, null, null, null, null, null, null]. It should be always [0, 1, null, null, null, null, null, null, null, null, null, null].

I watched the source code of the CopyOnWriteArrayList, and didn't find the answer to the strange results.

please help me work it out, thanks!

When adding a element you are effectively shifting the list, not replacing at that index so when adding on at 0 the one at position 1 becomes position 2. So the 2nd element being null will occur whenever the insert to position 1 occurs before 0. ie:

CopyOnWriteArrayList<String> ll = new CopyOnWriteArrayList<String>(new String[10]);
ll.add(1, "1");
ll.add(0, "0");
System.out.println(ll); 

>>> [0, null, 1, null, null, null, null, null, null, null, null, null]

This doesn't happen all the time because generally since you start the thread that inserts the 0 first. If you flip the order in which you are spawning your threads you will see it almost constantly.

I think what you are looking for is the "set" method

list.set(code, String.valueOf(code));

Changing to it will give the output you are expecting. Also worth mentioning the COWList is thread safe so the synchronization on writeList is not necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM