【问题标题】:CopyOnWriteArrayList remove logicCopyOnWriteArrayList 删除逻辑
【发布时间】:2015-11-22 13:13:52
【问题描述】:

在每个线程中我想运行这种代码 初始化列表

 final int initialSize = 2000;
        final Random rand = new Random(System.currentTimeMillis());
        Thread creationThread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int j = 0; j < initialSize; j++) {
                    list.add(rand.nextInt(10000));
                }
            }
        });
        creationThread.start();
        creationThread.join();
        List<Thread> threads = new ArrayList<Thread>();
        final int threadElemAmount = initialSize / numberOfThreads;

创建删除线程

 for (int i = 0; i < numberOfThreads; i++) {
        threads.add(new Thread(new Runnable() {
            @Override
            public void run() {
                for (int j = 0; j < threadElemAmount; j++) {
                        list.remove((int) (list.size() - 1));
                }
            }
        }));
    }

但我遇到了ArrayIndexOutOfBoundsException 读写问题。如何避免这种情况?

【问题讨论】:

  • 铸造需要什么?
  • 为什么你使用循环而不使用变量 i?
  • @Rehman hm,听不懂你的意思。
  • 使用迭代器。发生的情况是您的列表在一个线程中缩小,但其他线程继续在整个长度上运行。
  • 什么是threadElemAmount 给详细一点,代码不清楚

标签: java multithreading arraylist thread-safety


【解决方案1】:

如果你只是想确保你的删除操作成功,那么通过列表同步你的代码,比如:

public void run() {
    for (int j = 0; j < threadElemAmount; j++) {
        synchronized (list) {
            list.remove((int) (list.size() - 1));
        }
    }
}

还请放心,您正在通过同一个列表实例进行同步。

问题是由以下事实引起的:

list.remove((int) (list.size() - 1));

是这样处理的:

1: int tempVal = list.size() - 1;
2: list.remove(tempVal);

在您的情况下,线程 A 正在执行第 1 行,将执行上下文产生给执行 1 和 2 的线程 B,然后线程 A 抛出异常。

【讨论】:

  • 不仅如此,JAVA API 明确指出“如果多个线程同时访问一个 ArrayList 实例,并且至少有一个线程在结构上修改了列表,则必须在外部同步。” docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html 因此,即使您要删除位置 0 处的元素,您也必须同步对 ArrayList 的访问。
  • 谢谢,我知道这个可能的解决方案,但只有解决这个问题的方法吗?因为我已经使用了线程安全的 CopyOnWriteArrayList.java。只是外部同步?
  • @Palo,你读过问题的标题了吗?他正在使用CopyOnWriteArrayList,它允许并发修改。
  • @Palo 我没有使用 ArrayList 请再看一次
  • 对不起,谢谢。请粘贴代码的所有相关部分。在您的代码示例中,无法推断变量列表的类型。但是正如@user3707125 解释的那样,您的访问仍然需要同步。删除第一个元素而不是最后一个元素似乎是同样(无效)的方式,并且可以在不同步的情况下解决您的任务。 CopyOnWriteArrayList 对您来说是必需的吗?您不能只使用同步的 ArrayList 吗?这样会更有效率……
猜你喜欢
  • 2014-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-16
  • 2017-10-22
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多