CopyOnWriteArrayList线程安全问题

今天在学习CopyOnWriteArrayList原理的时候,发现一个问题。
CopyOnWriteArrayList更新操作是先复制原数组,然后在新数组上修改,之后再将原数组的引用指向新数组。

/** The lock protecting all mutators */
    final transient ReentrantLock lock = new ReentrantLock();

    /** The array, accessed only via getArray/setArray. */
    private transient volatile Object[] array;

    /**
     * Gets the array.  Non-private so as to also be accessible
     * from CopyOnWriteArraySet class.
     */
    final Object[] getArray() {
        return array;
    }

    /**
     * Sets the array.
     */
    final void setArray(Object[] a) {
        array = a;
    }
    /**
     * Replaces the element at the specified position in this list with the
     * specified element.
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            E oldValue = get(elements, index);

            if (oldValue != element) {
                int len = elements.length;
                Object[] newElements = Arrays.copyOf(elements, len);
                newElements[index] = element;
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }

在多线程条件下,分别是对原数组进行复制,即A线程复制原数组修改,然后更新;B线程复制原数组修改,然后更新。如果A线程修改的同时,B线程也进行操作。就会出现B线程修改的内容 覆盖了A线程的修改。

public void func() throws InterruptedException {
        CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 3; i++) {
            list.add(i);
        }
        Thread t1 = new Thread() {
            @Override
            public void run() {
                try {
                    sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                list.set(0, -1);
            }
        };
        Thread t2 = new Thread() {
            @Override
            public void run() {
                try {
                    sleep(80);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                list.set(1, -1);
            }
        };
        Thread t3 = new Thread() {
            @Override
            public void run() {
                try {
                    sleep(60);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                list.set(2, -1);
            }
        };
        t1.start();
        t2.start();
        t3.start();
        Thread.sleep(100);
        System.out.println(list.toString());
    }

运行3次,结果分别是

第一次:[0, -1, -1]
第二次:[0, -1, -1]
第三次:[-1, -1, -1]

按照我目前的理解,同一个代码,多次运行结果不一致,是线程不安全的。CopyOnWriteArrayList不能保证线程安全
如果理解有误的地方,请大家提出讨论

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值