Is ArrayList.add (int index, E element) a thread unsafe?

My previous question led me to this question.

Is adding a function to an ArrayList stream safe?

I made an example application with the following classes

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; } } 

These are my flows

 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(); } } } } 

This is my dummy class.

 public class DummyObject { } 

Despite the fact that I was not able to throw the Null Pointer Exception that I received in the previous question the previous question , sometimes I get this error

 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) 

The ArrayList Code form is a string that throws an error:

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

But, as can be seen from Exception , the index is 1 and the size is 10 , so there is no way for the condition to be satisfied. My assumption is true that adding the arrayList function is thread unsafe or is something else happening here?

+4
source share
3 answers

From the documentation :

(This class is roughly equivalent to Vector, except that it is unsynchronized.)

You need to either implement synchronization yourself, or even better, use a synchronized container, such as Vector .

In the case of your code, you have 2 threads that run the same piece of code ( loadObject ), in which several static values โ€‹โ€‹are available or changed. You must ensure that each access is synchronized. You have 2 threads, so you ThreadTest.list field ThreadTest.list , so one of the distributions is useless, but more importantly, there may be some values โ€‹โ€‹inserted into this list before it is lost, so these values โ€‹โ€‹are also lost.

You must make sure that the list is not highlighted before it is distributed.

You may also have a problem with the isLoaded field, which will result in more than 10 items in your list.

+4
source

The short answer is no, it is not thread safe. From JavaDoc

Please note that this implementation is not synchronized. If multiple threads access the ArrayList instance at the same time, and at least one of the threads modifies the list structurally, it must be synchronized from the outside. (A structural modification is any operation that adds or removes one or more elements or explicitly changes the size of the support array; just setting the value of an element is not a structural modification.) This is usually done by synchronizing on some object that naturally encapsulates the list. If such an object does not exist, the list should be โ€œwrappedโ€ using the Collections.synchronizedList method. This is best done at creation time to prevent accidental unsynchronized access to the list:

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

In general, none of the modern collections in Java is thread safe. If you just want them to not explode, you can use Collections.synchronizedList , as suggested in the JavaDoc. However, it is worth noting that this means that only one thread can access the collection at a time. This makes it safe, but can cause thread blocking problems.

If you are trying to get high concurrency, then you really want to see the java.util.concurrent package . This gives you cool classes like ArrayBlockingQueue , which makes this ArrayBlockingQueue stream very simple. Take a better look at Executor , which can handle this complexity.

+4
source

I put the actual code of the add method of the ArrayList class.

 /** * 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++; } 

Here, this method indicates that it is not thread safe, since elementData is

  private transient Object[] elementData; 

which is updated and in multi-threaded environments can cause a vital problem.

0
source

Source: https://habr.com/ru/post/1446403/


All Articles