As I Know only one thread can execute on a synchronize method on same block but in below producer consumer problem I am able to run both the methods.
Sample Code
import java.util.concurrent.CountDownLatch;
public class VIV {
public static void main(String[] args) throws Exception {
Number no = new Number();
//Same Object is passed
Even ev = new Even(no, 10);
Odd od = new Odd(no, 10);
Thread oddThraed = new Thread(od,"ODD");
oddThraed.start();
Thread evenThraed = new Thread(ev,"Even");
evenThraed.start();
}
}
class Number {
int no;
boolean flag=false;
public synchronized int getEvenNo() {
System.out.println("In Even Method");
// wait block so no other thread can enter on same object synchronized method
try{
wait();
}catch (Exception e) {
// TODO: handle exception
}
if(!flag) {
try {
Thread.sleep(1000);
}catch (Exception e) {
// TODO: handle exception
}
}
no=no+1;
System.out.println(Thread.currentThread().getName()+":"+no);
flag=false;
notify();
return no;
}
public synchronized int getOddNo() {
System.out.println("In ODD Method");
// wait block so no other thread can enter on same object synchronized method
try{
wait();
}catch (Exception e) {
// TODO: handle exception
}
if(flag) {
try{
wait();
}catch (Exception e) {
// TODO: handle exception
}
}
no = no+1;
System.out.println(Thread.currentThread().getName()+":"+no);
flag=true;
notify();
return no;
}
}
class Even implements Runnable {
Number num;
int noOfTime;
Even(Number no, int noOfTime) {
this.num=no;
this.noOfTime=noOfTime;
}
public void run() {
for(int i=0;i<noOfTime;i++) {
num.getEvenNo();
}
}
}
class Odd implements Runnable {
Number num;
int noOfTime;
Odd(Number no, int noOfTime) {
this.num=no;
this.noOfTime=noOfTime;
}
public void run() {
for(int i=0;i<noOfTime;i++) {
num.getOddNo();
}
}
}
OutPut :
- In ODD Method
- In Even Method
As Only one Number object is created and passed to other classes which are invoking on its two different synchronized methods. Both methods are printing the message after that waiting .
The reason that both methods get executed at the same time is that the wait()
method releases the lock. Once your synchronized
method calls wait()
, the lock is given back, and another thread can invoke another synchronized
method on the same object. Don't call wait()
inside a synchronized
method in this way!
The wait()
calls are also the reason that you're getting deadlock. This is what is happening:
- The
odd
method acquires the lock and starts executing.
- The
odd
method prints its first message.
- The
odd
method invokes wait()
, which releases the lock and waits to be notified.
- The
even
method can now acquire the lock that's been released.
- The
even
method prints its first message.
- The
even
method invokes wait()
, which releases the lock and waits to be notified.
By this point, you're in the middle of both synchronized
methods (because wait()
releases the lock), and you're deadlocked (because both methods are waiting).
Don't call wait()
unless you're quite sure that's what you need. If your wait()
is there just to keep it waiting to see if the synchronization can be broken, you might try Thread.sleep()
instead, which will pause without releasing any locks. Usually it's enough to declare the relevant methods or blocks as synchronized
without needing any wait
/ notify
.
(By the way, it's not a good idea to have a class called Number
, because this is a standard JDK class. It's the superclass of Double
, Integer
, and so on.)
I don't know whether you are trying to achieve this kind of thing, if you are trying to call EVEN & ODD alternatively, then I have modified your code for the same. Have a look at below code :-
public class VIV {
public static void main(String[] args) throws Exception {
TestNumber no = new TestNumber();
// Same Object is passed
Even ev = new Even(no, 10);
Odd od = new Odd(no, 10);
Thread oddThraed = new Thread(od, "ODD");
oddThraed.start();
Thread evenThraed = new Thread(ev, "Even");
evenThraed.start();
}
}
class TestNumber {
int no;
boolean flag = false;
public synchronized int getEvenNo() {
System.out.println("In Even Method");
// wait block so no other thread can enter on same object synchronized
// method
no = no + 1;
System.out.println(Thread.currentThread().getName() + ":" + no);
flag = false;
notify();
try {
wait();
} catch (Exception e) {
// TODO: handle exception
}
if (!flag) {
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
}
return no;
}
public synchronized int getOddNo() {
System.out.println("In ODD Method");
no = no + 1;
System.out.println(Thread.currentThread().getName() + ":" + no);
flag = true;
notify();
// wait block so no other thread can enter on same object synchronized
// method
try {
wait();
} catch (Exception e) {
// TODO: handle exception
}
if (flag) {
try {
wait();
} catch (Exception e) {
// TODO: handle exception
}
}
return no;
}
}
class Even implements Runnable {
TestNumber num;
int noOfTime;
Even(TestNumber no, int noOfTime) {
this.num = no;
this.noOfTime = noOfTime;
}
public void run() {
for (int i = 0; i < noOfTime; i++) {
num.getEvenNo();
}
}
}
class Odd implements Runnable {
TestNumber num;
int noOfTime;
Odd(TestNumber no, int noOfTime) {
this.num = no;
this.noOfTime = noOfTime;
}
public void run() {
for (int i = 0; i < noOfTime; i++) {
num.getOddNo();
}
}
}
Note : As suggested by @chiastic-security Number is already defined in JDK, I have renamed it to TestNumber in this code.
Output :
In ODD Method
ODD:1
In Even Method
Even:2
In ODD Method
ODD:3
In Even Method
Even:4
In ODD Method
ODD:5
In Even Method
Even:6
In ODD Method
ODD:7
In Even Method
Even:8
In ODD Method
ODD:9
In Even Method
Even:10
In ODD Method
ODD:11
In Even Method
Even:12
In ODD Method
ODD:13
In Even Method
Even:14
In ODD Method
ODD:15
In Even Method
Even:16
In ODD Method
ODD:17
In Even Method
Even:18
In ODD Method
ODD:19
In Even Method
Even:20