首先我不在这里使用迭代器。
我在共享的ArrayList上使用2个线程,1st用于向ArrayList添加值,其他用于创建它的临时副本并对其执行一些操作,然后从原始列表中删除所有临时元素。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ArraylistTest {
public static void main(String...ar){
new AddingThread().start();
new RemovalThread().start();
}
}
class RemovalThread extends Thread{
static List<Integer> originalBigList = new ArrayList<>();
@Override
public void run(){
System.out.println("RemovalThread started");
while(true){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("creating copy of originalBigList");
List<Integer> tempList = new ArrayList<>(originalBigList);
System.out.println("copied list");
//
//some operations on copied temp list
//
System.out.println("removing tempList elements after completing operations");
System.out.println("originalBigList before removing size "+originalBigList.size());
originalBigList.removeAll(tempList);
System.out.println("removed!!");
System.out.println("after size "+originalBigList.size());
}
}
}
class AddingThread extends Thread{
@Override
public void run(){
System.out.println("Adding thread started");
int ctr = 0;
while(true){
RemovalThread.originalBigList.add(ctr);
ctr++;
}
}
}
输出: -
Adding thread started
RemovalThread started
creating copy of originalBigList
copied list
removing tempList elements after completing operations
originalBigList before removing size 4102267
Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.add(ArrayList.java:458)
at AddingThread.run(ArraylistTest.java:47)
现在我的问题是我在输出中看到正在复制列表的语句被执行,它正在从原始列表中生成临时列表,但是删除语句没有执行而且没有给出任何异常和我&# 39; m使用简单的arraylist不同步,为什么会这样呢?
删除或添加操作时是否有内部锁?如果是,那么Collections.synchronised(arraylist)的用途是什么?
答案 0 :(得分:2)
以下一行
List<Integer> tempList = new ArrayList<>(originalBigList);
将通过originalBigList遍历列表构造函数来创建你的tempList,如果AddingThread将在paralel中运行,它将抛出杀死你的RemovalThread的ConcurrentModificationException,也许你在控制台中看不到它,但它可能就在那里。我会为你的originalBigList
使用CopyOnWriteArrayList答案 1 :(得分:2)
我发现你的问题看下面的代码
public static void main(String ...args){
long start = System.currentTimeMillis();
List<Integer> l1 = new ArrayList<>();
List<Integer> l2 = new ArrayList<>();
for(int i = 0 ; i < Integer.MAX_VALUE/10000;i++){
l1.add(i);
l2.add(i);
}
System.out.println(String.format("Field both arrays in %s seconds",(System.currentTimeMillis()-start)/1000) );
start = System.currentTimeMillis();
l1.removeAll(l2);
System.out.println(String.format("Removed one array from other %s seconds",(System.currentTimeMillis()-start)/1000) );
}
在0秒内对两个数组进行分析
从其他34秒内删除了一个数组
这是一个巨大的数组,现在看看输出删除需要花费大量的时间,在你的情况下,AddingThread使得数组变得庞大,所以它的工作只需要很多时间,同时,AddingThread一直在工作。顺便说一下,为什么需要首先找到每个值需要这么长时间才能理解为什么它是O(n ^ 2)。当我使用HashSet而不是List时注意它是如何工作的(注意:HashSet搜索是O(1))
public class HashSetTest {
public static Object obj = new Object();
public static void main(String... ar) {
new AddingThread().start();
new RemovalThread().start();
}
}
class RemovalThread extends Thread {
static Set<Integer> originalBigSet = new HashSet<>();
@Override
public void run() {
System.out.println("RemovalThread started");
while (true) {
try {
sleep(1000);
System.out.println("creating copy of originalBigSet");
Set<Integer> tempList;
synchronized (HashSetTest.obj) {
tempList = new HashSet<>(originalBigSet);
}
System.out.println("copied list");
//
//some operations on copied temp list
//
System.out.println("removing tempList elements after completing operations");
System.out.println("originalBigSet before removing size " + originalBigSet.size());
synchronized (HashSetTest.obj) {
originalBigSet.removeAll(tempList);
}
System.out.println("removed!!");
System.out.println("after size " + originalBigSet.size());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class AddingThread extends Thread {
@Override
public void run() {
System.out.println("Adding thread started");
int ctr = 0;
while (true) {
synchronized (HashSetTest.obj) {
RemovalThread.originalBigSet.add(ctr);
}
ctr++;
}
}
}
答案 2 :(得分:1)
与@urag的答案类似(特别是关于O(n²)的说法),您可以通过修改AddingThread
来看到效果,因此它只添加了有限数量的项目:
class AddingThread extends Thread{
@Override
public void run(){
System.out.println("Adding thread started");
int ctr = 0;
while(true){
if (ctr < 100_000) {
RemovalThread.originalBigList.add(ctr);
ctr++;
}
}
}
}
这导致:
Adding thread started
RemovalThread started
creating copy of originalBigList
copied list
removing tempList elements after completing operations
originalBigList before removing size 100000
removed!!
after size 0
现在,将100_000
更改为1_000_000
,您将等待很长时间,只看到::
Adding thread started
RemovalThread started
creating copy of originalBigList
copied list
removing tempList elements after completing operations
originalBigList before removing size 1000000