The following code does not work as I expect it to:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
class Worker implements Runnable {
public void run() {
System.out.println("Started.");
process();
}
private Random random = new Random();
private Object lock1 = new Object();
private Object lock2 = new Object();
private static List<Integer> list1 = new ArrayList<Integer>();
private static List<Integer> list2 = new ArrayList<Integer>();
public void stageOne() {
synchronized (lock1) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
list1.add(random.nextInt(100));
}
}
public void stageTwo() {
synchronized (lock2) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
list2.add(random.nextInt(100));
}
}
public void process() {
for(int i=0; i<1000; i++) {
stageOne();
stageTwo();
}
}
public static void show() {
System.out.println("List1: " + list1.size());
System.out.println("List2: " + list2.size());
}
}
public class JavaTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
Thread t1 = new Thread(new Worker());
t1.start();
Thread t2 = new Thread(new Worker());
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Completed.");
long end = System.currentTimeMillis();
System.out.println("Time taken: " + (end - start));
Worker.show();
}
}
When I run this program, I expect list1
and list2
to contain 2000 items each and for the program to take approximately 2000 milliseconds. However, lots of times I get lists less than 2000 items, although it does finish around 2000 milliseconds. Sometimes I even get a ArrayOutOfBounds
Exception
Started.
Started.
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 163
at java.util.ArrayList.add(ArrayList.java:459)
at Worker.stageOne(JavaTest.java:34)
at Worker.process(JavaTest.java:53)
at Worker.run(JavaTest.java:14)
at java.lang.Thread.run(Thread.java:748)
Completed.
Time taken: 2217
List1: 1081
List2: 1079
I expect that each the locks in stageOne
and stageTwo
should stop the threads from interfering with each other. But that does not seem to be the case. What is the problem with this code?
So in your case, Thread mt1 acquires lock on Object mt1 and Thread mt2 acquires lock on Object mt2 and they do not block each Other as the two threads are working on two different locks. And when two threads modify a shared variable concurrently(not synchronized way), the result is unpredictable.
Synchronization is built around an internal entity known as the lock or monitor. Every object has a lock associated with it. By convention, a thread that needs consistent access to an object's fields has to acquire the object's lock before accessing them, and then release the lock when it's done with them.
Synchronized blocks in Java are marked with the synchronized keyword. A synchronized block in Java is synchronized on some object. All synchronized blocks synchronize on the same object can only have one thread executing inside them at a time.
A Synchronized block is used to lock an object for any shared resource and the scope of a synchronized block is smaller than the synchronized method.
Your lock objects are not static, so each thread is synchronizing on a different monitor. So the locks are not having any effect at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With