I am trying to do something like this:
There is a class Q
which has a field called n
and two methods put()
and get()
which sets the value of n or retrieves the value of n. And then there are two classes Producer
and Consumer
. Producer
class has a thread which calls put
and consumer
class has a thread which calls get
. I am trying to synchronize it using an Object lock
which is the only instance of Singleton class LockClass.
So, here is my class Q :
public class Q {
int n;
public void put(int n){
System.out.println("Put " + n);
this.n = n;
}
public int get(){
System.out.println("Got " + n);
return n;
}
}
LockClass:
public class LockClass {
private static Object Lock = new Object();
private LockClass(){
}
public static Object getLock(){
return Lock;
}
}
Consumer:
public class Consumer implements Runnable {
Thread t;
Q q;
public Consumer(Q q){
this.q = q;
t = new Thread(this);
t.start();
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
synchronized(LockClass.getLock()){
q.get();
}
try {
System.out.println("Consumer slept");
Thread.sleep(1000);
System.out.println("Consumer awake");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Producer:
public class Producer implements Runnable {
Q q;
Thread t;
int i;
public Producer(Q q){
this.q = q;
t = new Thread(this);
t.start();
i = 0;
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
i++;
synchronized(LockClass.getLock()){
q.put(i);
}
try {
System.out.println("Producer slept");
Thread.sleep(1000);
System.out.println("Producer awake");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
DemoClass : This class has the main function
public class DemoClass {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Q q = new Q();
Producer prod = new Producer(q);
Consumer cons = new Consumer(q);
}
}
So, when I run this above code, I get something like this :
Put 1
Producer slept
Got 1
Consumer slept
Consumer awake
Producer awake
Got 1
Consumer slept
Put 2
Producer slept
Consumer awake
Producer awake
Got 2
Consumer slept
Put 3
Producer slept
Consumer awake
Producer awake
Got 3
Consumer slept
Put 4
Producer slept
So, I am actually making the thread sleep in both producer and consumer so that there is enough time for context switching. Now when both needs to sleep for same time, if producer sleeps first, it should get awake first . But as I can see in output, the producer sleeps first but still consumer awakes first and as whichever thread gets awake first should get the lock and so another thread should wait till the lock is released.
Why is it not working the way I am expecting? Am I missing something?
The sleep timeout is not guaranteed to be strict, so it's absolutely valid that one thread can sleep later and wake earlier. Quotation from Thread.sleep java doc:
[...] subject to the precision and accuracy of system timers and schedulers
Theoretically it's even possible for one thread to make the action twice, while second thread will be sleeping.
If you want two threads to act one after another, use wait-notify mechanism:
producer
Object lock = LockClass.getLock();
synchronized(lock){
q.put(i);
lock.notifyAll();
lock.wait();
}
consumer
Object lock = LockClass.getLock();
synchronized(lock){
q.get(i);
lock.notifyAll();
lock.wait();
}