Reputation: 2616
I came across a Java problem about multi-threaded programming (please see the code below). Based on this question and answer on StackOverflow, I think I understand why there could be a deadlock. But what I don't understand was if the program works correctly (i.e. there is no deadlock), what would be the value of foo
printed? I thought it would be 20 (thread1 counting up to 10 and thread2 counting up to 10 more). Could someone help me explain how this might (preferably in a simple way because I'm still new to thread programming)? Thank you.
public class ThreadTest{
private static class ThreadOne extends Thread{
private ThreadTwo threadTwo;
public int foo = 0;
public void setThreadTwo(ThreadTwo th){
threadTwo = th;
}
public void run(){
try{
for(int i=0;i<10;i++) foo += i;
synchronized(this){this.notify();};
synchronized(threadTwo){threadTwo.wait();};
System.out.print("Foo: " + threadTwo.foo);
}catch(InterruptedException e){ e.printStackTrace();}
}
}
private static class ThreadTwo extends Thread{
private final ThreadOne threadOne;
public int foo = 0;
public ThreadTwo(ThreadOne th){
threadOne = th;
}
public void Run(){
try{
synchronized(threadOne){threadOne.wait();}
foo = threadOne.foo;
for(int i=0;i<10;i++) foo += i;
synchronized(this){this.notify();};
}
catch(InterruptedException e){e.printStackTrace();}
}
}
public static void main(){
ThreadOne th1 = new ThreadOne();
ThreadTwo th2 = new ThreadTwo(th1);
th1.setThreadTwo(th2);
th1.start(); th2.start();
th1.join(); th2.join();
}
}
Upvotes: 1
Views: 86
Reputation: 3199
According to your code and without deadlocks foo
value will be 90 (if i didn't miscalculate). Because instead of foo += 1
you did foo += i
.
EDIT: Okay, step by step.
foo
= 0th1
and th2
starts. th2
waits for notify. th1
increments foo
up to 45th1
notifies and starts to wait th2
. th2
is notified and starts to increment foo
from 45 to 90th2
notifies th1
. th1
is notified, and it prints th2.foo
, which is 90EDIT 2: Correct way to count from 0 to 90 from 2 threads without concurrent modification is something like this
public class ThreadTest {
private static int counter = 0;
private static class Thread1 extends Thread {
final Object lock;
public Thread1(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
for (int i = 0; i < 10; i++)
counter += i;
}
}
}
private static class Thread2 extends Thread {
final Object lock;
public Thread2(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
for (int i = 0; i < 10; i++)
counter += i;
}
}
}
public static void main(String[] args) {
final Object lock = new Object();
final Thread th1 = new Thread1(lock);
final Thread th2 = new Thread2(lock);
th1.start();
th2.start();
try {
th1.join();
th2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Counter: " + counter);
}
}
But if you are forced to use wait
and notify
, than it's a bit more complicated. Use object of this class as common lock instead of Object
class Locker {
private boolean isLocked = false;
public synchronized void lock() throws InterruptedException {
while (isLocked) wait();
isLocked = true;
}
public synchronized void unlock() {
isLocked = false;
notify();
}
}
And in run
method us it like this:
@Override
public void run() {
try {
locker.lock();
for (int i = 0; i < 10; i++)
counter += i;
locker.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Upvotes: 1