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

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.

Related

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.

Understanding the Thread Safety of Array list

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.

why is this synchronized method not working as expected? [duplicate]

This question already has an answer here:
why Synchronized method allowing multiple thread to run concurrently?
(1 answer)
Closed 7 years ago.
I have a class called MyRunnable:
public class MyRunnable extends Main implements Runnable {
String name; // name of thread
Thread t;
MyRunnable (String threadname) {
name = threadname;
t = new Thread(this, name);
t.start();
}
public void run() {
try {
for (int i=0;i<100000;i++) {
extend(1);
}
} catch (InterruptedException e) {
System.out.println("Thread interrupted.");
}
System.out.println("Thread " + name + " exiting.");
}
}
and a class called Main:
public class Main {
private static List<Integer> numbers=new ArrayList<>();
public synchronized void extend (int i) throws InterruptedException {
numbers.add(i);
}
public synchronized static int getSize() {
return numbers.size();
}
public static void main(String[] args) {
MyRunnable t0=new MyRunnable("0");
MyRunnable t1=new MyRunnable("1");
MyRunnable t2=new MyRunnable("2");
try {
t0.t.join();
t1.t.join();
t2.t.join();
} catch (InterruptedException e) {
}
System.out.println(getSize());
}
}
Now I would be expecting to get 300000 as output but instead I get a random number (approx. between 250000 and 290000) even though I did use synchronized methods. I did read the oracle's documentation http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html but I can't seem to figure out why this is not working as expected. Could someone explain me why ?
Thanks in advance
Methods are synchronized to the object calling them. You need to create an object shared between each of the objects and have them synchronize on that object.
private static List<Integer> numbers=new ArrayList<>();
public synchronized void extend (int i) throws InterruptedException {
synchronize(numbers) {
numbers.add(i);
}
}
synchronized here locks on the object against which the method extend is invoked (since it is an instance method). Therefore, you're synchronizing on three different objects.
If you synchronize on the shared static list (for example), you would get the expected result.

Java basic synchronized threads [duplicate]

This question already has answers here:
Odd even number printing using thread
(13 answers)
Closed 8 years ago.
I am learning Java but have trouble with synchronized. i want print list of numbers from many Java threads and have each thread go in order.I get problem when using synchronized because i not much understand. Can help understand?
I want output to see this but sometimes threads in wrong order.i want:
1-thread1
2-thread2
3-thread1
4-thread2
5-thread1
6-thread2
...
48-thread2
49-thread1
My broken codes:
public class ManyThreadsAdd {
public static int index = 0;
public static void main(String[] args) {
ManyThreadsAdd myClass = new ManyThreadsAdd();
Thread thread1 = new Thread(myClass.new RunnableClass());
Thread thread2 = new Thread(myClass.new RunnableClass());
thread1.start();
thread2.start();
}
class RunnableClass implements Runnable {
public synchronized void run() {
while (index < 49) {
try {
Thread.sleep(100);
System.out.println(index+"-" +Thread.currentThread());
index = index + 1;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
It depends on what you want to do.
A simple way to alternate the order of the print is to synchronize on the same object, in this case you can use the index or any other object.
public class ManyThreadsAdd {
public static AtomicInteger index = new AtomicInteger(0);
public static void main(String[] args) {
ManyThreadsAdd myClass = new ManyThreadsAdd();
Thread thread1 = new Thread(myClass.new RunnableClass());
Thread thread2 = new Thread(myClass.new RunnableClass());
thread1.start();
thread2.start();
}
class RunnableClass implements Runnable {
public void run(){
synchronized(index){
while(index.get() < 49){
try {
Thread.sleep(100);
System.out.println(index.get()+"-" +Thread.currentThread());
index.incrementAndGet();
index.notify();
index.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
Firstly, multithreading by nature is asynchronous, you cannot specify the order in which these threads get executed. If you want output like below, use a loop:
1-thread1
2-thread2
3-thread1
4-thread2
5-thread1
6-thread2
...
48-thread2
49-thread1
Secondly, you gain nothing by adding the synchronized keyword in public synchronized void run(). This just means that at any time, only one thread at a time can call that method. As you are constructing new classes for each thread, this is meaningless.
Thirdly, if you did need to synchronise between your threads, use a queue to which you add tasks, and which your threads read one at a time.

Java - Synchronized

Hi i have made a something that extends thread that adds adds an object that has a IP in it. then i made two instances of this thread and started them. they use the same list.
I now want to use Synchronized to stop the concurrent update problem. But its not working and i cant work out why.
My main class:
import java.util.*;
import java.io.*;
import java.net.*;
class ListTest2 {
public static LinkedList<Peer> myList = new LinkedList<Peer>();
public static void main(String [] args) {
try {
AddIp test1 = new AddIp(myList);
AddIp test2 = new AddIp(myList);
test1.start();
test2.start();
} catch(Exception e) {
System.out.println("not working");
}
}
}
My thread class:
class AddIp extends Thread {
public static int startIp = 0;
List<Peer> myList;
public AddIp(List<Peer> l) {
myList = l;
}
public synchronized void run() {
try {
startIp = startIp+50;
int ip = startIp;
InetAddress address = InetAddress.getByName("127.0.0.0");
Peer peer = new Peer(address);
while(ip <startIp+50) {
ip++;
address = InetAddress.getByName("127.0.0."+ip);
peer = new Peer(address);
myList.add(peer);
if(myList.indexOf(peer)== (myList.size() -1)) {
} else {
System.out.println("Lost"+peer.peerIp);
}
}
} catch(Exception e) {
}
}
}
Can anyone help me out here im lost for ideas thanks.
public synchronized void run()
Synchronizes on calling instance: this.
So,
1st thread synchronizes on test1 and 2nd thread synchronizes on test2, which doesn't help at all.
You want to synchronize on the shared resource, in this case: myList
public void run() {
synchronize(myList){
//your Logic
}
}
As a side note: Implement runnable instead of extending a Thread. Read more here.
You'd be better off implementing Runnable oppose to extending thread
also
public void run() {
synchronize(list){
//stuffs
}
}
they use the same list.
You can try to use Vector instead List. Vector is synchronized
or set your List to be synchronized:
List myList = Collections.synchronizedList(myList);
instead to use:
synchronize(myList){
}
The easiest way is to use a List implementation that can handle multiple threads. Try CopyOnWriteArrayList.

Categories