Why Unsynchronized ArrayList Object add method is not behaving properly - java

Here is the sample code
1) ArrayList is a single object which is passed to every thread of ThreadPool.
2) At end of execution list size should be 50, if you check the sample outputs its may not 50. Sometime it may be 41 or 47 like that, why it is behaving like that.
public class Test {
ArrayList list=new ArrayList();
public static void main(String[] args) {
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);
Test test=new Test();
for(int i=0;i<5;i++)
{
Mythread t1=new Mythread(test.list);
executorService3.execute(t1);
}
executorService3.shutdown();
while(executorService3.isShutdown())
{
//---This is not giveging proper output as expected is 50.--
System.out.println("List size="+test.list.size());
break;
}
}
}
class Mythread implements Runnable {
List list=null;
Mythread(List list) {
this.list=list;
}
#Override
public void run() {
for(int i=0;i<10;i++) {
this.list.add(i);
}
}
}

Your code isn't waiting for the threads to finish execution. By the time your code calls the following line
System.out.println("List size="+test.list.size());
there's no guarantee that they have finished, and so no guarantee that the list contains the expected 50 items. Use the awaitTermination method (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#awaitTermination(long,%20java.util.concurrent.TimeUnit)), e.g.:
executorService3.shutdown();
executorService3.awaitTermination(1, TimeUnit.SECONDS);
System.out.println("List size="+test.list.size());
(Exception handling omitted for brevity)

As it says in the Javadoc for ArrayList:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
So it's "not behaving properly" because you're not using it as described in the documentation.
As is suggested in the Javadoc, you can wrap your list in a synchronized list:
List<Integer> list = Collections.synchronizedList(new ArrayList<>());

It's a concurrency problem.
The way i see it, you have :
5 threads that will execute the run method on the same object. Multiple threads can insert a variable, on the same position in the array list, since it is not synchronized.
Could you print the content of your list ?

Related

Is my below code thread safe while removing elments from LinkedBlockingQueue?

I have a below method which is called by multiple threads concurrently to get the live socket. It takes LinkedBlockingQueue as the parameter and then I iterate and see if there is any liveSocket available and if it is available then I remove and return that socket.
private Optional<Holder> getSocket(final LinkedBlockingQueue<Holder> endPoints) {
Optional<Holder> liveSocket = Optional.absent();
if (!endPoints.isEmpty()) {
for (Holder state : endPoints) {
// check if socket is live? if yes then remove and return that.
if (state.isLive()) {
liveSocket = Optional.of(state);
endPoints.remove(state);
return liveSocket;
}
}
}
return Optional.absent();
}
Wanted to check if my above code is thread safe or not? Here Holder is an immutable class.
The queue manipulation operations are thread safe, so the remove() will not throw ConcurrentModificationException. However, you have thread-safety problems around the state of the objects contained in the queue.
There's a race condition between when you check the "live" state of the Holder object and when you remove it from the queue. Another thread could be running in the same code at the same time, with the likely result that both threads would take the same object. Whichever thread got to the remove() call last would get a false return, but you don't examine the result so you'd never know. Both threads would then attempt to use the same object.
You need to synchronize around the search/remove operation.
For curiosity, here's the code I used to show that ConcurrentModificationException does not occur with LinkedBlockingQueue:
public static void main(String[] args) throws Exception
{
String[] data = { "a", "b", "c", "d", "e", "f","g" };
LinkedBlockingQueue<String> lb = new LinkedBlockingQueue<>(Arrays.asList(data));
new Thread(() ->
{
try
{
Thread.sleep(2000);
lb.add("x");
System.out.println("added");
Thread.sleep(1000);
lb.remove("e");
System.out.println("removed");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}).start();
for (String s : lb)
{
System.out.println(s);
Thread.sleep(1000);
}
}
If you substitute LinkedList for LinkedBlockingQueue you get the ConcurrentModificationException as expected.
Output:
a
b
added
c
removed
d
f
g
x
It's not only not thread-safe, it's wrong even within a single thread. You will get a ConcurrentModificationException on the remove(). You need to use an explicit Iterator and to do the removal via the Iterator.
And for correctness via multiple threads you need synchronization or a semaphore around the loop.
NB The isEmpty() test is pointless. The iteration already has to check for that. Don't keep a dog and bark yourself.

Creating a lock on List<String> or Hastable<String,String>

A List of String or Hastable of (String,String) type that contains certain values.
I have situation where multiple threads are running and I want each thread to use only one of the values from the above mentioned lists.
Example:
List - Set1,Set2,Set3
If Thread1 is using Set1 and thread2 tries to use one of the values in the list, It should get only Set2 and Set3 as available. Set1 should be available when Thread1 is done.
you could implement it by locking on the List and removing/adding the appropriate Set before starting/after finishing the work:
public class ListLock {
private List<Set<String>> list = new ArrayList<>();
//initialize with some values
public ListLock(List<Set<String>> availableValues) {
this.list = availableValues;
}
//this will allow your Thread to get an available value. Your Thread needs to keep the selected value until the job is done and put it back
public void synchronized aquireValue(Selector selector) {
//this one is little bit tricky, you provide some interface, that has 1 method, that will call a "select" function on your Thread.
Set<String> selected = selector.select(list);
this.list.remove(selected);
}
//after job is done, put the value back in the list, so it's available for another Thread
public void synchronized releaseValue(Set<String> value) {
this.list.add(value);
}
}
of course you could use generics to make this class more general

Why do I need to synchronize this variable

I have 4 threads each trying to find the max value in a linked list.
This is my thread class:
public class MyThread extends Thread {
LinkedList<Integer> list;
int max = Integer.MIN_VALUE;
public MyThread(LinkedList<Integer> list) {
this.list = list;
}
public void run() {
synchronized (list) { /* If I don't synchronize list, I get a NoSuchElementException at list.remove() */
while (!list.isEmpty()) {
int num = list.remove();
if (num > max) {
max = num;
}
}
}
}
}
And here is the class with the main method:
public class Application {
public static void main(String args[]) throws InterruptedException {
LinkedList<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
MyThread t1 = new MyThread(list);
MyThread t2 = new MyThread(list);
MyThread t3 = new MyThread(list);
MyThread t4 = new MyThread(list);
t1.start();
t2.start();
t3.start();
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();
System.out.println(t1.max);
System.out.println(t2.max);
System.out.println(t3.max);
System.out.println(t4.max);
}
}
In the above code, I have to synchronize the list variable within the run method or else I'll get a NoSuchElementException at list.remove(). Why is this the case?
Doesn't each thread have it's own list so there is no thread interference?
Thanks
I will address a different part of your question that #Rishi addressed:
Doesn't each thread have it's own list so there is no thread interference?
The simple answer is: No, it does not. In Java, when you pass an object of class type to a constructor or method, you aren't passing the obejct itself but rather a pointer to it. If you want to pass a separate copy of the linked list to each thread, you need to use LinkedList#Clone.
If you use clone, then when a thread removes one integer from its linked list, it will not be removed from the other linked lists. To properly paralellize this, you should use a standard array with all of your numbers and assign a segment of this array to each thread (ie. thread 1 does 0-9, thread 2 does 10-19, thread 3 does 20-29, etc.). The array's contents will be visible to any threads created after the contents are deposited in the array.
I should also note that you should not extend Thread. Instead, extend Runnable and pass it to a thread. Furthermore, an array(list) would be better than 4 separate variables as it allows you to easily change the number of threads later.
LinkedList is not thread-safe. Hence it would need external synchronization if you operate on LinkedList with more than one thread.
You can use BlockingQueue, whose poll() method would come handy in this case.

Java, adding elements in an array an concurrently looping through it

Sorry if this is a dumb question. But could someone explain me what could happens in a scenario like this?
List<Integer> scores = new Arraylist<>() ;
scores =
Collections.synchronizedList(scores)
public void add(int element) {
...
scores.add(element)
...
}
public String retrieve(int element) {
...
For (Integer e : scores)....
....
Return something
}
Let's assume that this class is a singelton and that scores is global. Multiple thread can add and retrieve the scores at the same time
In this scenario when starting the for loop and at the same time a thread is adding (or removing an element from the list) will it throw a concurrent modification exeption ?
Thank you
Bad things will happen, given the way you've written your example.
Your retrieve() method doesn't have its loop in a synchronized block, and both of your methods are accessing scores directly, instead of using the List returned by the Collections.synchronizedList() method.
If you take a look at the API for Collections.synchronizedList(), you'll notice that it says
In order to guarantee serial access, it is critical that all access to the backing list is accomplished through the returned list.
It is imperative that the user manually synchronize on the returned list when iterating over it:
Failure to follow this advice may result in non-deterministic behavior.
So you might get a ConcurrentModificationException, or something else weird might happen.
Edit
Even if all your access is via the synchronized List, you can still end up getting a ConcurrentModificationException thrown at you if you modify the List while iterating over it in another thread. That's why the Collections.synchronizedList() documentation insists that you manually wrap your iteration inside a block that is synchronized on the List it returns.
The API for ConcurrentModificationException says
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Your add method won't need to be changed, but your retrieve() method should look something like:
public String retrieve(int element) {
// stuff
synchronized (scores) { // prevent scores from being modified while iterating
for (Integer e : scores) {
// looping stuff
}
}
// more stuff
return something;
}
Sample Program
Here's a small sample program which demonstrates the behavior of safe vs unsafe access:
public class Scratch {
private List<Integer> scores = Collections.synchronizedList(new ArrayList<Integer>());
public static void main(String[] args) throws Exception {
final Scratch s = new Scratch();
s.scores.add(1);
s.scores.add(2);
s.scores.add(3);
// keep adding things to the list forever
new Thread(new Runnable() {
#Override
public void run() {
try {
int i=100;
while (true) {
Thread.sleep(100);
s.scores.add(i++);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
System.out.println("This will run fine");
s.safeLoop();
System.out.println("This will cause a ConcurrentModificationException");
s.unsafeLoop();
}
public void safeLoop() throws InterruptedException {
synchronized (scores) {
for (int i : scores) {
System.out.println("i="+i);
Thread.sleep(100);
}
}
}
public void unsafeLoop() throws InterruptedException {
for (int i : scores) {
System.out.println("i="+i);
Thread.sleep(100);
}
}
}

Data race in Java ArrayList class

I was reading about CopyOnWriteArrayList and was wondering how can I demonstrate data race in ArrayList class. Basically I'm trying to simulate a situation where ArrayList fails so that it becomes necessary to use CopyOnWriteArrayList. Any suggestions on how to simulate this.
A race is when two (or more) threads try to operate on shared data, and the final output depends on the order the data is accessed (and that order is indeterministic)
From Wikipedia:
A race condition or race hazard is a flaw in an electronic system or process whereby the output and/or result of the process is unexpectedly and critically dependent on the sequence or timing of other events. The term originates with the idea of two signals racing each other to influence the output first.
For example:
public class Test {
private static List<String> list = new CopyOnWriteArrayList<String>();
public static void main(String[] args) throws Exception {
ExecutorService e = Executors.newFixedThreadPool(5);
e.execute(new WriterTask());
e.execute(new WriterTask());
e.execute(new WriterTask());
e.execute(new WriterTask());
e.execute(new WriterTask());
e.awaitTermination(20, TimeUnit.SECONDS);
}
static class WriterTask implements Runnable {
#Override
public void run() {
for (int i = 0; i < 25000; i ++) {
list.add("a");
}
}
}
}
This, however, fails when using ArrayList, with ArrayIndexOutOfbounds. That's because before insertion the ensureCapacity(..) should be called to make sure the internal array can hold the new data. And here's what happens:
the first thread calls add(..), which in turn calls ensureCapacity(currentSize + 1)
before the first thread has actually incremented the size, the 2nd thread also calls ensureCapacity(currentSize + 1).
because both have read the initial value of currentSize, the new size of the internal array is currentSize + 1
the two threads make the expensive operation to copy the old array into the extended one, with the new size (which cannot hold both additions)
Then each of them tries to assign the new element to array[size++]. The first one succeeds, the second one fails, because the internal array has not been expanded properly, due to the rece condition.
This happens, because two threads have tried to add items at the same time on the same structure, and the addition of one of them has overridden the addition of the other (i.e. the first one was lost)
Another benefit of CopyOnWriteArrayList
multiple threads write to the ArrayList
a thread iterates the ArrayList. It will surely get ConcurrentModificationException
Here's how to demonstrate it:
public class Test {
private static List<String> list = new ArrayList<String>();
public static void main(String[] args) throws Exception {
ExecutorService e = Executors.newFixedThreadPool(2);
e.execute(new WriterTask());
e.execute(new ReaderTask());
}
static class ReaderTask implements Runnable {
#Override
public void run() {
while (true) {
for (String s : list) {
System.out.println(s);
}
}
}
}
static class WriterTask implements Runnable {
#Override
public void run() {
while(true) {
list.add("a");
}
}
}
}
If you run this program multiple times, you will often be getting ConcurrentModificationException before you get OutOfMemoryError.
If you replace it with CopyOnWriteArrayList, you don't get the exception (but the program is very slow)
Note that this is just a demonstration - the benefit of CopyOnWriteArrayList is when the number of reads vastly outnumbers the number of writes.
Example:
for (int i = 0; i < array.size(); ++i) {
Element elm = array.get(i);
doSomethingWith(elm);
}
If another thread calls array.clear() before this thread calls array.get(i), but after it has compared i with array.size(), -> ArrayIndexOutOfBoundsException.
Two threads, one incrementing the arraylist and one decrementing. Data race could happen here.

Categories