2017-06-27 27 views
0

首先我没有在这里使用迭代器。我无法从Java共享ArrayList中删除元素,同时添加到它

我在一个共享的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) 

现在我的问题是,我看到在其中复制列表中的语句被执行,正在从最初的名单列表温度的输出,但去除语句没有执行,也没有给出任何异常,我使用简单的arraylist不同步,那么为什么这样呢?

移除或添加操作时是否有内部锁定?如果是,那么Collections.synchronised(ArrayList)有什么用?

+1

ArrayList是不是线程安全的? – LazerBanana

+0

2在2分钟内向上提问?是的,这看起来不像投票欺诈。 – Tom

+1

嘿汤姆为什么有-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保持工作。顺便说一句,它是UND可持续的原因为什么需要这么长时间才需要首先找到每个值,因此它是O(n^2)。看看它是如何工作的时候我用的不是List HashSet的(注: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++; 
    } 
} 

}

+0

感谢Urag的清晰解释,赞赏。 –

+0

乐意帮忙:) – urag

2

下面一行

  List<Integer> tempList = new ArrayList<>(originalBigList); 

将列出构造函数中遍历originalBigList创建您tempList如果AddingThread将在运行相同常会抛出,也许你杀死你RemovalThread没有看到它在控制台中的ConcurrentModificationException的但它可能在那里。我会sugest使用的CopyOnWriteArrayList您originalBigList

+0

我也认为它会给根据Java文档ConcurrentModification异常,但它不给我运行这个代码几次,我做了总是给出相同的输出。 –

+0

你怎么知道它并没有试图把所有的块都放在里面,并打印出异常?因为如果在调试时执行此操作,它的行为可能会有所不同 – urag

+0

好的,我没有尝试捕获,但是如果它发生,那么它应该被JVM的运行时环境捕获,并将在控制台中显示。但它没有,并且如果我使用CopyOnWriteArrayList,那么我有大量的写操作,所以在每次写入时它都会创建一个新列表,我认为这是不可行的。 –

1

类似于@urag的回答(尤其是关于O(n2)的说法),您可以通过修改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_0001_000_000,你会等待很长的时间,只看到::

Adding thread started 
RemovalThread started 
creating copy of originalBigList 
copied list 
removing tempList elements after completing operations 
originalBigList before removing size 1000000 
+0

Tkanks Urag,EmreSevinç –