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
Related
I'm getting this error for the code below
First thread about to sleep
thread 1 run
Boolean assignment done.
Woke up and about to invoke wait()
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at IncorrectSynchronization$1.run(HelloWorld.java:23)
at java.lang.Thread.run(Thread.java:748)
When the Thread t1 is sleeping, I modified the lock to false from another thread.
It then throws this IllegalMonitorStateException. It's still the same object, why would modifying the value cause IllegalMonitorStateException?
When I modify the lock to false from another thread inside a synchronized block, I no longer get that error. Can anyone explain the reason for what's happening under the hood?
public class HelloWorld{
public static void main( String args[] ) throws InterruptedException {
SampleTest.runExample();
}
}
class SampleTest{
Boolean flag = new Boolean(true);
public void example() throws InterruptedException {
Thread t0 = new Thread(new Runnable() {
public void run() {
synchronized (flag) {
try {
while (flag) {
System.out.println("First thread about to sleep");
Thread.sleep(2000);
System.out.println("Woke up and about to invoke wait()");
flag.wait();
System.out.println("wait() called");
}
} catch (InterruptedException ie) {
}
}
}
});
Thread t1 = new Thread(new Runnable() {
public void run() {
System.out.println("thread 1 run");
flag = false;
}
});
t0.start();
Thread.sleep(200);
t1.start();
t0.join();
t1.join();
}
public static void runExample() throws InterruptedException {
SampleTest test = new SampleTest();
test.example();
}
}
The problem is with this line:
flag = false;
This changes the reference of the flag Boolean variable, from the original Boolean object (which is created by the deprecated constructor which should not be used) to the pre-created Boolean.FALSE instance (due to autoboxing). By the time the first thread calls flag.wait(), the object is no longer the same as the one it used to synchronize, hence the IllegalMonitorStateException.
In this scenario, it's much better to use an AtomicBoolean and mutate its value in the other thread:
AtomicBoolean flag = new AtomicBoolean(true);
Now the second thread can update the value of the same object. It should also probably notify the first thread that is waiting on the object (like wait(), notify() also requires synchronizing on the object on which it is invoked):
Thread t1 = new Thread(new Runnable() {
public void run() {
synchronized(flag) {
System.out.println("thread 1 run");
flag.set(false);
flag.notify();
}
}
});
It is pretty unsafe to iterate over a List, which is being performed add / remove operation by another thread.
That's why we need need CopyOnWriteArrayList
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
// java.util.ConcurrentModificationException
for (String s : list) {
System.out.println(s);
}
}
}
});
thread.start();
for (int i=0; i<1000; i++) {
list.add("string" + i);
}
Thread.sleep(Long.MAX_VALUE);
}
However, how about set operation. Currently, the following code doesn't throw any exception.
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
list.add("dummy");
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
for (String s : list) {
System.out.println(s);
}
}
}
});
thread.start();
for (int i=0; i<1000; i++) {
list.set(0, "smart");
}
Thread.sleep(Long.MAX_VALUE);
}
Even though there isn't any unexpected outcome, I was wondering, if the thread only performing set operation on the List, is it a good practice that we don't using any locking mechanism, or copy n write mechanism?
Quoting the javadoc of 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. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.)
So no, it does not need to be synchronized.
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.
I have two Threads classes "AddThread" and "ReadThread". The execution of these threads should be like this "AddThread should add 1 record and wait until ReadThread displays the record after that ReadThread should display that added record again AddThread should add another record" this process should continue untill all the records are added(REcords are accessed from LinkedList). Here is the code
class AddThread extends Thread
{
private Xml_Parse xParse;
LinkedList commonlist;
AddThread(LinkedList commonEmpList)
{
commonlist = commonEmpList;
}
public void run()
{
System.out.println("RUN");
xParse=new Xml_Parse();
LinkedList newList=xParse.xmlParse();
try
{
synchronized (this) {
if(newList.size()>0)
{
for(int i=0;i<newList.size();i++)
{
System.out.println("FOR");
commonlist.add(newList.get(i));
System.out.println("Added" +(i+1)+ "Record");
}
System.out.println(commonlist.size());
}
}
}
catch(Exception e)
{
}
}
}
class ReadThread extends Thread
{
LinkedList commonlist;
ReadThread(LinkedList commonEmpList)
{
commonlist = commonEmpList;
}
public void run()
{
try
{
synchronized (this) {
System.out.println();
System.out.println("ReadThread RUN");
sleep(1000);
//System.out.println("After waiting ReadThread RUN");
System.out.println(commonlist.size());
if(commonlist.size()>0)
{
for(int j=0;j<commonlist.size();j++)
{
System.out.println("Read For");
System.out.println("EmpNo: "+((EmployeeList)commonlist.get(j)).getEmpno());
System.out.println("EmpName: "+((EmployeeList)commonlist.get(j)).getEname());
System.out.println("EmpSal: "+((EmployeeList)commonlist.get(j)).getEmpsal());
}
}
}
}
catch(Exception e)
{
}
}
}
public class MainThread
{
public static LinkedList commonlist=new LinkedList();
public static void main(String args[])
{
AddThread addThread=new AddThread(commonlist);
ReadThread readThread=new ReadThread(commonlist);
addThread.start();
readThread.start();
}
}
You'll need to learn how to effectively use wait() and notify().
See also:
Guarded Blocks
What about using a BlockingQueue with a capacity of 1? Use offer instead of add so that producer thread is blocked.
You might also consider using a Semaphore with one permit, making it a mutex.
You use join() and yield() to control flux. If you want the current thread to stop and wait until the new thread finishes the work,
t1.run()
t.join()
when t1 finishes t continues.
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.)