ArrayList.add(int index,E element)线程不安全吗?

时间:2012-11-16 09:10:02

标签: java multithreading arraylist thread-safety

我的Previous question让我想到了这个问题。

ArrayList线程的add function是否安全?

我使用以下类创建了一个示例应用程序

import java.util.ArrayList;
import java.util.List;


public class ThreadTest
{
    public static List<DummyObject> list = null;
    public static boolean isLoaded = false;
   public static void main(String [] args)
   {
      MyThread t1 = new MyThread(1);
      MyThread t2 = new MyThread(2);

      t1.start();
      t2.start();
   }

   public static void loadObject(){
       if(isLoaded){
           return;
       }
       isLoaded = false;
       try{
       list = new ArrayList<DummyObject>();
       for(int i=0;i<10;i++){
           list.add(i,new DummyObject());
       }}
       catch(Exception e){
           e.printStackTrace();
       }
       isLoaded = true;
   }
}

这些是我的主题

public class MyThread extends Thread
{
   int threadNumber ;
   public MyThread(int threadNumber)
   {
      this.threadNumber = threadNumber;
   }

   @Override
   public void run()
   {
       try {
        sleep(10-threadNumber);
    } catch (InterruptedException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
     System.out.println("Running Thread: " + threadNumber);
     ThreadTest.loadObject();
     if(ThreadTest.isLoaded){
         System.out.println(ThreadTest.list);
         for(int i=0;i<ThreadTest.list.size();i++){
             if(ThreadTest.list.get(i)==null){
                 throw new NullPointerException();
             } 
         }
     }else {
         try {
                sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
         }
   }
}

这是我的虚拟课

public class DummyObject {

}

即使我无法复制previous question上的Null Pointer Exception,我有时会收到此错误

Exception in thread "Thread-1" java.lang.IndexOutOfBoundsException: Index: 1, Size: 10
    at java.util.ArrayList.add(ArrayList.java:367)
    at ThreadTest.loadObject(ThreadTest.java:25)
    at MyThread.run(MyThread.java:20)

Form ArrayList Code这是抛出错误的行:

if (index > size || index < 0)
        throw new IndexOutOfBoundsException(
        "Index: "+index+", Size: "+size);

但是我们可以从Exception中看到 index为1且size为10 ,因此如果条件满足则无法实现。那么我的假设是正确的,即arrayList的add函数是不安全的还是其他的东西?

3 个答案:

答案 0 :(得分:4)

来自documentation

  

(这个类大致相当于Vector,除了它是不同步的。)

您需要自己实现同步,或者更好的是,使用像Vector这样的同步容器。

对于代码,您有2个线程运行相同的代码段(loadObject),其中访问/修改了几个静态值。您需要确保每个访问都以同步方式完成。 你有两个线程,因此你分配了ThreadTest.list字段的两倍,所以其中一个分配是没用的,但更重要的是,在它丢失之前可能会在该列表中插入一些值,因此这些值也会丢失

您应确保在分配列表之前未分配列表。

您也可能遇到isLoaded字段的问题,导致列表中包含10个以上的元素。

答案 1 :(得分:4)

简短的回答,不,这不是线程安全的。来自JavaDoc

  

请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。 (结构修改是添加或删除一个或多个元素的任何操作,或显式调整后备数组的大小;仅设置元素的值不是结构修改。)这通常通过同步一些自然封装的对象来实现。名单。如果不存在此类对象,则应使用Collections.synchronizedList方法“包装”该列表。这最好在创建时完成,以防止意外地不同步访问列表:

List list = Collections.synchronizedList(new ArrayList(...));

通常,Java中的所有现代集合都不是线程安全的。如果您只是想让它们不被炸毁,您可以使用JavaDoc中建议的Collections.synchronizedList。但值得注意的是,这只意味着一次只有一个线程可以访问该集合。这确实使其安全,但可能导致线程被阻止的问题。

如果你想获得高并发性,那么你真的想看看java.util.concurrent package。这为你提供了很好的类ArrayBlockingQueue,这使得这种线程非常容易。更好的是,看看Executor实现可以为您处理很多这种复杂性。

答案 2 :(得分:0)

我已经放置了add类的ArrayList方法的实际代码。

/**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

此处此方法声明它不是线程安全的,因为elementData

 private transient Object[] elementData;

,已更新,在多线程环境中,它可能会导致严重的问题。