Understanding the Thread Safety of Array list - java

I am trying to understand how ArrayList is not thread safe through a java program.Attached is my program.
import java.util.ArrayList;
import java.util.List;
public class class1
{
static List ar=new ArrayList(1);
public static void main(String[] args) throws InstantiationException,
IllegalAccessException, ClassNotFoundException, InterruptedException
{
Thread t1= new Thread()
{
public void run()
{
while(true)
{
ar.add(new Object());
}
}
};
Thread t2=new Thread()
{
public void run()
{
while(true)
{
ar=new ArrayList(1);
ar.add(new Object());
ar.add(new Object());
}
}
};
t1.start();
Thread.sleep(100);
t2.start();
}
}
The error i got is:
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 2
at java.util.ArrayList.add(Unknown Source)
at class1$1.run(class1.java:22)
I understand that the exception is caused by a thread.However,I am not getting a broader picture on how it is actually functioning.Any help would be highly appreciated.

Look at ArrayList.Add code.
Array list is based on arrays. If array is full - arrayList expands it's length on 2. To expand an array it has to be copied. Looks like your code breaks down when "add" called in one thread expands the arrya and trying to copy data - but another thread changes the reference.

Related

How to make java.util.ArrayList threadsafe [duplicate]

This question already has answers here:
How do I make my ArrayList Thread-Safe? Another approach to problem in Java?
(8 answers)
Closed 2 years ago.
I have logic similar to below in my program which throws ConcurrentModificationException. How can I make java.util.ArrayList threadsafe other than using CopyOnWriteArrayList (because I have large number of write on this list and as per my understanding writes are expensive on CopyOnWriteArrayList)
import java.util.ArrayList;
import java.util.List;
public class Test extends Thread {
List<String> list = new ArrayList<String>();
public static void main(String[] args) {
Test t = new Test();
t.start();
System.out.println("in main thred");
t.destory();
}
public void destory() {
list.stream().toArray(String[]::new);
System.out.println("done");
}
#Override
public void run() {
while(true) {
list.add("test");
}
}
}
Output:
in main thred
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1388)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:546)
at java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
at java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:438)
You have to synchronize all accesses to the list:
public void destory() {
synchronized (list) {
list.stream().toArray(String[]::new);
}
System.out.println("done");
}
and
while(true) {
synchronized (list) {
list.add("test");
}
}
Note that it is not sufficient simply to wrap the list in Collections.synchronizedList, since that won't hold the monitor for the entirety of the iteration by the stream.

While adding element into ArrayList using Multithreading, sometimes it give ConcurrentModificationException and sometimes not?

I tried iterating ArrayList object using multi-threading, but sometimes it is giving ConcurrentModificationException and sometimes not? I am unable to understand what is happening here.
I am sharing my code below:
import java.util.ArrayList;
import java.util.Iterator;
public class ConcurrentDemo extends Thread{
static ArrayList l=new ArrayList();
public void run()
{
/*
* try { Thread.sleep(2000); } catch(InterruptedException e) { }
*/
System.out.println("child thread updating list");
l.add("D");
System.out.println(l);
}
public static void main(String args[]) throws InterruptedException
{
l.add("A");
l.add("B");
l.add("c");
ConcurrentDemo c=new ConcurrentDemo();
c.start();
System.out.println(l);
Iterator itr =l.iterator();
while(itr.hasNext())
{
String s1=(String)itr.next();
System.out.println("main thread list:" + s1);
Thread.sleep(3000);
}
System.out.println(l);
}
}
Please see my answer inline in your code:
import java.util.ArrayList;
import java.util.Iterator;
public class ConcurrentDemo extends Thread{
static ArrayList l=new ArrayList();
public void run()
{
System.out.println("child thread updating list");
l.add("D");
System.out.println(l);
}
public static void main(String args[]) throws InterruptedException
{
//----> Main thread starts here
l.add("A");
l.add("B");
l.add("c");
//----> l now contains A,B,C
ConcurrentDemo c=new ConcurrentDemo();
//----> You have started a second thread here
c.start();
//-----> Its not determined, which line will be executed first from now on, as 2 threads are running parallelly, the ConcurrentModificationException most likely occur in cases, when the "l.add("D");" called within the "run();" method AFTER the Iterator has been created.
System.out.println(l);
Iterator itr =l.iterator();
while(itr.hasNext())
{
String s1=(String)itr.next();
System.out.println("main thread list:" + s1);
Thread.sleep(3000);
}
System.out.println(l);
}
}
Please note regarding to interators, that the behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling the appropriate method on the Iterator interface.Reference
Instead of randomly failing when you do this, the collection is nice
enough to keep track of how many times it's been modified, and throw
ConcurrentModificationException when it detects concurrent
modification. Reference
If you plan to modify the underlying collection of an iterator by adding new elements, consider using the ListIterator
Example with your code:
static ArrayList l=new ArrayList();
ListIterator listItr =l.listIterator();
listItr.add(e);
For further informations, check out this Java Concurrency and Multithreading tutorial.
EDIT:
As it might be hard to notice, I am highlighting the most important inline comment within the code above:
After you have called c.start(); its not determined, which line will be executed first, as 2 threads are running parallelly, the ConcurrentModificationException most likely occur in cases, when the l.add("D"); called within the run(); method after the Iterator has been created.

Java- Why this program not throwing concurrent Modification exception

I am trying to induce a concurrent modification exception by accessing a HashMap instance variable reference, but this program is not throwing the error. Appreciate if you could help me to understand.
package Threads;
import java.util.HashMap;
public class ProducerConsumer {
private HashMap<String, String> sharedMap = new HashMap<String,String>();
public void putMethod(){
for (int count=0; count<100; count++)
{
System.out.println("Adding into sharedMap:"+count);
sharedMap.put(Integer.toString(count),Integer.toString(count));
}
}
public static void main(String [] args) throws InterruptedException{
final ProducerConsumer pc1=new ProducerConsumer();
Thread t1= new Thread( new Runnable(){
#Override
public void run() {
pc1.putMethod();
}
});
Thread t2= new Thread( new Runnable(){
#Override
public void run() {
pc1.putMethod();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
The add() method does not detect concurrent modifications and therefore will not throw a ConcurrentModificationException (that's what anonymous already said).
However, concurrent access to a HashMap can be dangerous, though. Read more about this in another post.
You can enforce a ConcurrentModificationException if you read from the HashMap in parallel:
...
public void putMethod() { ... }
public void iterateMethod() {
sharedMap.keySet().stream().forEach((s) -> {
System.out.println("Read key " + s);
}
}
public static void main(String[] args) throws InterruptedException {
...
t1.start();
Thread.sleep(20); // sleep time depends on your computer's speed ;-)
t2.start();
...
}
...
The exception needs to be thrown by the implementing method that is being invoked on the class. From the Javadoc, it looks like the HashMap Iterators are fast-fail Iterators; meaning it will throw it if you are Iteratoring while adding. The add method will add the item to the map if the key doesn't exist or replace it if it does, I don't think that would throw the exception you're trying to produce.

Non deterministic behavior with synchronizedList

I am trying to understand the concept of Collections.synchronizedList() but the below code does not work properly.According to my understanding, synchronizedList will synchronise all methods of ArrayList and putting it inside synchronised block will prevent other thread from accessing/modification of object on which lock is acquired.Below is my code.
public class SynchronisedList {
/**
* #param args
*/
static ArrayList<String> list=new ArrayList<String>();
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0;i<50000;i++)
list.add("String"+i);
final List<String> list1=Collections.synchronizedList(list);
Thread thread=new Thread(new Runnable() {
#Override
public void run() {
System.out.println("Thread 1 started");
synchronized (list1)
{
for(int i=0;i<50000;i++)
{
System.out.println(list1.get(i));
//System.out.println(list.get(i));
}
}
}
});
Thread thread1=new Thread(new Runnable() {
#Override
public void run() {
System.out.println("Thread 2 started");
list1.clear();
}
});
thread.start();
thread1.start();
}
}
My expected output is Thread 1 will iterate will through arraylist list1 and then Thread 2 will clear it.but I am getting error as,
Exception in thread "Thread-0" java.lang.IndexOutOfBoundsException: Index: 432, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.get(ArrayList.java:322)
at java.util.Collections$SynchronizedList.get(Collections.java:1816)
at com.common.List.SynchronisedList$1.run(SynchronisedList.java:35)
at java.lang.Thread.run(Thread.java:619)
Am I doing any wrong here?Please help.
to achieve your exepcted output, both iteration and clearing should be in asynchronized block, and you should synchronized on the original list, list1 is redundant

A query regarding Java Threads

Please let me know how I can print “After wait”; how can I notify main thread in the following code:
import java.util.*;
public class Test {
public static void main(String[] args) throws InterruptedException {
ArrayList al = new ArrayList(6);
al.add(0, "abc");
al.add(1, "abc");
al.add(2, "abc");
synchronized(al){
System.out.println("Before wait");
al.wait();
System.out.println("After wait");
}
}
}
The wait() call is blocking until someone notify()s it... Basically, you would need to create a new thread that calls al.notify() when the main thread is blocking in wait().
This program prints Before wait, pauses for one second, and prints After wait.
import java.util.ArrayList;
public class Test {
public static void main(String[] args) throws InterruptedException {
final ArrayList al = new ArrayList(6);
al.add(0, "abc");
al.add(1, "abc");
al.add(2, "abc");
// Start a thread that notifies al after one second.
new Thread() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (al) {
al.notify(); // <-- this "releases" the wait.
}
}
}.start();
synchronized (al) {
System.out.println("Before wait");
al.wait();
System.out.println("After wait");
}
}
}
Here is a link to one of my previous answers, explaining why wait() and notify() must be executed while holding the lock of the monitor.
Why must wait() always be in synchronized block
You're not creating any other threads, so it's hard to see how there is anything else to notify the main thread. However, if you did have another thread which had a reference to al, you'd use something like:
synchronized(al) {
al.notify();
}
or
synchronized(al) {
al.notifyAll();
}
(The difference between the two is that notify will only wake a single thread from waiting; notifyAll will wake all the threads waiting on that object.)

Categories