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.
Related
Why am I not getting 20000 when the increment method is synchronized. I did the same thing with runnable and it worked.
public class ThreadClass extends Thread
{
static int count=0;
public synchronized void increment()
{
count++;
}
public void run()
{
for(int i=0;i<10000;i++)
{
increment();
}
};
}
public class Main {
public static void main(String[] args) {
ThreadClass t1=new ThreadClass();
ThreadClass t2= new ThreadClass();
t1.start();
t2.start();
try {
t2.join();
t1.join();
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println(ThreadClass.count);
}
}
The JLS, for synchronized methods, clearly states the following:
For an instance method, the monitor associated with this (the object for which the method was invoked) is used.
As a result, the two ThreadClass instances will lock independently, and there will be no common lock protecting bad writes to count.
Synchronize explicitly on Threadclass.class or make increment() static to actually synchronize in a manner that makes writes safe.
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.
I have this small sample of code, while modifying the list, i lock it with synchronized, but while reading the list it comes to ConcurrentModificationException, because without "synchronized" the lock has no effect. Is it possible to lock an object for all threads which use the object, even the un-synchronized, too?
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Test {
public static void main(String[] args) {
final Random r = new Random(System.currentTimeMillis());
List<Integer> list = new ArrayList<>();
new Thread(new Runnable() {
public void run() {
while (true) {
synchronized (list) {
list.add(r.nextInt());
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
for (Integer i : list) {
System.out.println(i);
}
}
}
}).start();
}
}
the backgorund is that i dont want to change all pieces in my code which read the object
You might consider using a concurrent implementation of List, instead of ArrayList. Perhaps a CopyOnWriteArrayList.
final List<Integer> list = new CopyOnWriteArrayList<Integer>();
Is it possible to lock an object for all threads which use the object.
In a word, No. When one thread enters a synchronized(foo) {...} block, that does not prevent other threads from accessing or modifying foo. The only thing it prevents is, it prevents other threads from synchronizing on the same object at the same time.
What you can do, is you can create your own class that encapsulates both the lock and the data that the lock protects.
class MyLockedList {
private final Object lock = new Object();
private final List<Integer> theList = new ArrayList<>();
void add(int i) {
synchronized(lock) {
theList.add(i);
}
}
void printAll() {
synchronized(lock) {
for (Integer i : theList) {
System.out.println(... i ...);
}
}
}
...
}
If you can modify the function which concurrently uses the object, just add synchronized in every critical section:
while (true) {
synchronized(list){
for (Integer i : list) {
System.out.println(i);
}
}
}
if you can't , create a specified lock that is responsible for locking the threads:
Lock lock = new Lock();
new Thread(new Runnable(){
//...
synchronized(lock){
do unsynchonized function on list
}
//...
}).start();
new Thread(new Runnable(){
//...
synchronized(lock){
do unsynchonized function on list
}
//...
}).start();
the latter may slow down the process if one of the functions already doing some locking, but in this way you can ensure you always synchronize the access to concurrent objects.
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.
//The below code is throwing illegalmonitorstate exception.
public class Multithreading implements Runnable {
static int i=0;
public boolean ist1=true;
public boolean ist2=false;
public static void main (String args[]){
Multithreading ins= new Multithreading();
Thread t1 =new Thread(ins);
Thread t2 =new Thread(ins);
t1.setName("Even");
t2.setName("ODD");
t1.start();
t2.start();
}
#Override
// Wanted to right run method used by two threads to print
// even and odd number in sequence
public void run() {
while(i<=9){
try{
if(Thread.currentThread().getName().contains("Even")&& i%2==0){
System.out.println(Thread.currentThread().getName()+"________"+i);
i=i+1;
Thread.currentThread().wait(100);
}
// due to wait is not used with synchronized but
// i am not able to correct it
if(Thread.currentThread().getName().contains("ODD") && i%2>=1){
System.out.println(Thread.currentThread().getName()+"________"+i);
i=i+1;
Thread.currentThread().wait(100);
//System.out.println(e);
}
}catch(Exception e){
System.out.println(e);
}
}
}
}
To pause a thread, you need to use Thread.sleep() in your case instead of wait().