gpt4 book ai didi

java - Java ArrayList 类中的数据竞争

转载 作者:搜寻专家 更新时间:2023-11-01 02:54:45 25 4
gpt4 key购买 nike

我正在阅读有关 CopyOnWriteArrayList 的内容,想知道如何在 ArrayList 类中演示数据竞争。基本上,我试图模拟 ArrayList 失败的情况,因此有必要使用 CopyOnWriteArrayList。关于如何模拟这个的任何建议。

最佳答案

竞争是指两个(或更多)线程尝试对共享数据进行操作,最终输出取决于访问数据的顺序(并且该顺序是不确定的)

来自维基百科:

A race condition or race hazard is a flaw in an electronic system or process whereby the output and/or result of the process is unexpectedly and critically dependent on the sequence or timing of other events. The term originates with the idea of two signals racing each other to influence the output first.

例如:

public class Test  {
private static List<String> list = new CopyOnWriteArrayList<String>();

public static void main(String[] args) throws Exception {
ExecutorService e = Executors.newFixedThreadPool(5);
e.execute(new WriterTask());
e.execute(new WriterTask());
e.execute(new WriterTask());
e.execute(new WriterTask());
e.execute(new WriterTask());

e.awaitTermination(20, TimeUnit.SECONDS);
}

static class WriterTask implements Runnable {

@Override
public void run() {
for (int i = 0; i < 25000; i ++) {
list.add("a");
}
}
}
}

但是,当使用 ArrayListArrayIndexOutOfbounds 时,这会失败。这是因为在插入之前,应该调用 ensureCapacity(..) 以确保内部数组可以保存新数据。下面是发生的事情:

  • 第一个线程调用 add(..),后者又调用 ensureCapacity(currentSize + 1)
  • 在第一个线程实际增加大小之前,第二个线程也调用了 ensureCapacity(currentSize + 1)
  • 因为两者都读取了currentSize的初始值,所以内部数组的新大小为currentSize + 1
  • 这两个线程将旧数组复制到具有新大小的扩展数组中(不能容纳两个添加)
  • 然后他们每个人都尝试将新元素分配给array[size++]。第一个成功,第二个失败,因为接收条件导致内部数组未正确扩展。

发生这种情况是因为两个线程试图同时在同一结构上添加项目,并且其中一个的添加覆盖了另一个的添加(即第一个丢失了)

CopyOnWriteArrayList 的另一个好处

  • 多线程写入ArrayList
  • 一个线程迭代ArrayList。它肯定会得到 ConcurrentModificationException

下面是演示方法:

public class Test  {
private static List<String> list = new ArrayList<String>();

public static void main(String[] args) throws Exception {
ExecutorService e = Executors.newFixedThreadPool(2);
e.execute(new WriterTask());
e.execute(new ReaderTask());
}

static class ReaderTask implements Runnable {
@Override
public void run() {
while (true) {
for (String s : list) {
System.out.println(s);
}
}
}
}

static class WriterTask implements Runnable {
@Override
public void run() {
while(true) {
list.add("a");
}
}
}
}

如果您多次运行该程序,您通常会在 OutOfMemoryError 之前收到 ConcurrentModificationException

如果你用CopyOnWriteArrayList替换它,你不会得到异常(但是程序很慢)

请注意,这只是一个演示 - CopyOnWriteArrayList 的好处是读取次数大大超过写入次数。

关于java - Java ArrayList 类中的数据竞争,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3836680/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com