Odd even number printing using thread
Solution 1
You're waiting and notifying different objects (monitors).
The idea is that you can call obj.wait()
to wait for someone to do obj.notify()
, while you're doing objA.wait()
and objB.notify()
.
Change your printOdd
method to something like
private void printOdd(int i) {
synchronized (lock) { // <-------
while (!oddTurn) {
try {
lock.wait(); // <-------
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(type + i);
oddTurn = false;
lock.notifyAll(); // <-------
}
}
and the printEven
method similarly.
Then provide the NumberPrinter
with a lock
object:
Object lock = new Object();
Thread odd = new Thread(new NumberPrinter("odd", lock));
Thread even = new Thread(new NumberPrinter("even", lock));
Output:
odd1
even2
odd3
even4
odd5
even6
odd7
even8
odd9
Solution 2
There are a lot of bugs in the code.
First of all, the synchronized
statements have no effect whatsoever. You create two thread instances, and each calls only its own methods. synchronized
is only useful if another thread can call a method.
Then notifyAll()
has no effect for the same reasons. odd.notifyAll()
doesn't reach even
hanging in the wait()
.
So what you need is another object which contains the state and which both threads can see and use. Use synchronized
, wait()
and notifyAll()
on that third instance.
Solution 3
The same can be solved using Lock interface:
NaturalOrder.java
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class NaturalOrder {
public int currentNumber = 1;
public boolean evenOdd = false;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public static void main(String[] args) {
NaturalOrder naturalOrder = new NaturalOrder();
Thread t1 = new Thread(new OddNumberLock(naturalOrder, naturalOrder.lock, naturalOrder.condition));
Thread t2 = new Thread(new EvenNumberLock(naturalOrder, naturalOrder.lock, naturalOrder.condition));
t1.start();
t2.start();
}
}
OddNumberLock.java
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class OddNumberLock implements Runnable {
NaturalOrder naturalOrder;
Lock lock;
Condition condition;
public OddNumberLock(NaturalOrder naturalOrder, Lock lock, Condition condition) {
this.naturalOrder = naturalOrder;
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
lock.lock();
while (naturalOrder.currentNumber < 20) {
while (naturalOrder.evenOdd != false) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
if (naturalOrder.currentNumber % 2 != 0) {
System.out.println(naturalOrder.currentNumber);
}
naturalOrder.currentNumber++;
naturalOrder.evenOdd = true;
condition.signalAll();
}
lock.unlock();
}
}
EvenNumberLock.java
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class EvenNumberLock implements Runnable {
NaturalOrder naturalOrder;
Lock lock;
Condition condition;
public EvenNumberLock(NaturalOrder naturalOrder, Lock lock, Condition condition) {
this.naturalOrder = naturalOrder;
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
lock.lock();
while (naturalOrder.currentNumber < 20) {
while (naturalOrder.evenOdd != true) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
if (naturalOrder.currentNumber % 2 == 0) {
System.out.println(naturalOrder.currentNumber);
}
naturalOrder.currentNumber++;
naturalOrder.evenOdd = false;
condition.signalAll();
}
lock.unlock();
}
}
Solution 4
I did this way
public class OddEven{
public static void main(String[] args){
Print o=new Print();
Thread even=new Thread(new MyRunnable(2,o));
Thread odd=new Thread(new MyRunnable(1,o));
even.start();
odd.start();
}
}
class MyRunnable implements Runnable{
int start;
Print ob;
MyRunnable(int s,Print o){
start=s;
ob=o;
}
public void run(){
for(int i=start;i<=20;i+=2)
ob.display(i);
}
}
class Print{
int rem=0;
synchronized void display(int n){
while(n%2==rem)
try{
wait();
}
catch(Exception e){System.out.println("Display interrupted");}
System.out.print(n+" ");
rem=n%2;
notify();
}
}
Solution 5
I think the problem might be that printOdd
and printEven
synchronize on different lock (the Thread's object instance locks). Therefor you have not guaranteed that the change on the static variable oddTurn
will be visible in the other thread. Try to make the oddTurn
volatile for the start.
Comments
-
Sourabh over 1 year
Odd even number printing using thread.Create one thread class, two instance of the thread. One will print the odd number and the other will print the even number.
I did the following coding. But it comes to dead lock state. Can some one please explain what might be the reason for that?
public class NumberPrinter implements Runnable{ private String type; private static boolean oddTurn=true; public NumberPrinter(String type){ this.type=type; } public void run() { int i=type.equals("odd")?1:2; while(i<10){ if(type.equals("odd")) printOdd(i); if(type.equals("even")) printEven(i); i=i+2; } } private synchronized void printOdd(int i){ while(!oddTurn){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(type + i); oddTurn=false; notifyAll(); } private synchronized void printEven(int i){ while(oddTurn){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(type + i); oddTurn=true; notifyAll(); } public static void main(String[] s){ Thread odd=new Thread(new NumberPrinter("odd")); Thread even=new Thread(new NumberPrinter("even")); odd.start(); even.start(); } }
Out Put: odd1 even2
then comes to deadlock!!!!!!
Thanks for your help.
-
Sourabh almost 13 yearsThanks for your response. Even after using volatile also getting the same result. It is going to deadlock.
-
Vladimir Ivanov almost 13 yearsSee other answers, I have missed the fact, that yo uhave two objects, so no real synchronization is performed.
-
aioobe almost 13 years
volatile
doesn't matter. Both threads access different variables. -
aioobe almost 13 yearsYou don't need to let the common object to contain any state in this case. See my answer.
-
Aaron Digulla almost 13 yearsThat's true but it makes it more simple to see which state is shared between the two threads. Multithreaded programming is already complex enough without adding more complexity :-)
-
aioobe almost 13 yearsAgreed. Tasks like these should, unless they are part of some homework, also be coded using the
java.util.concurrent
package :)