在JAVA中发生了什么当两个并发线程试图从同一个CopyOnWriteArrayList中删除一些元素时?会有不确定的行为吗? 例如,如果列表中有1-10个整数, 1个线程删除前5个整数 2线程删除前3个整数 准确的结果是删除前5个整数的列表。 这会正常工作吗?
答案 0 :(得分:1)
CopyOnWriteArrayList的行为取决于您使用的方法。
如果你在一个线程中使用5 remove(int index)
而在另一个线程中使用3,那么你将删除8个元素,尽管哪个线程获得了未定义的元素。
如果你在一个线程中查找5个值remove(Integer element)
,而另一个线程中的前3个值是另一个线程,只要没有重复,前5个元素将被删除。前三个元素可以被任一个线程删除,留下没有删除元素的线程返回false
答案 1 :(得分:0)
CopyOnWriteArrayList
实际上用于多线程环境,其中最佳结果,其中写入较少,读取次数较多。
所有主题都带有List 的副本,原始列表左侧完好无损。在任何添加/删除操作之前,监视器会查看原始列表,每次写入列表时都会生成整个列表的副本,例如添加元素或删除元素synchronization
发生的情况。
当您的列表太大时,这可能相当昂贵。
这意味着CopyOnWriteArrayList
在我们进行少量修改但很多读取时非常有用,因为读取非常便宜并且不需要同步。
根据文件here,
java.util.ArrayList的线程安全变体,其中所有变量都是 操作(添加,设置等)通过重新实现来实现 基础数组的副本。
答案 2 :(得分:0)
如果按索引删除,则将删除总共8(5 + 3)个元素。 因为,在一个线程删除一个元素后,新的CopyOnWriteArrayList将具有比之前执行删除的元素更少的元素。
package com.copyonwrite;
import java.util.concurrent.CopyOnWriteArrayList;
public class Main {
public static void main(String[] args) {
CopyOnWriteArrayList<String> cop = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++)
cop.add(Integer.toString(i));
new Thread(new DeleteRunnable(cop, 5)).start();
new Thread(new DeleteRunnable(cop, 3)).start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("size " + cop.size());
}
public static class DeleteRunnable implements Runnable {
CopyOnWriteArrayList<String> cop;
int cnt;
public DeleteRunnable(CopyOnWriteArrayList<String> cop, int cnt) {
this.cop = cop;
this.cnt = cnt;
}
@Override
public void run() {
for (int i = 0; i < cnt; i++)
cop.remove(i);
}
}
}
输出:大小2