我正在尝试做这样的事情:
有一个类Q
,其中有一个名为n
的字段和两个方法put()
和get()
,它们设置n的值或检索n的值。然后有两个类Producer
和Consumer
。 Producer
类有一个调用put
的线程,consumer
类有一个调用get
的线程。我正在尝试使用Object lock
同步它,这是Singleton类LockClass.
的唯一实例
所以,这是我的班级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;
}
}
消费者:
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();
}
}
}
}
制片:
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:这个类有主函数
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);
}
}
所以,当我运行上面的代码时,我会得到这样的结果:
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
所以,我实际上是在生产者和消费者中使线程休眠,以便有足够的时间进行上下文切换。现在当两个人都需要同时睡觉时,如果生产者先睡觉,它应该首先醒来。但是正如我在输出中看到的那样,生产者先睡觉但仍然消费者首先醒来,并且首先唤醒哪个线程应该获得锁定,因此另一个线程应该等到锁定被释放。
为什么它不像我期待的那样工作?我错过了什么吗?
答案 0 :(得分:2)
来自doc:
......然而,这些睡眠时间并不能保证精确,因为 它们受底层操作系统提供的设施限制...... 无论如何,你不能假设调用睡眠 将在指定的时间段内暂停该主题
https://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html
答案 1 :(得分:1)
睡眠超时不保证是严格的,因此一个线程可以稍后睡眠并提前唤醒是绝对有效的。来自Thread.sleep java doc的报价:
[...]受制于系统定时器和调度程序的精确性和准确性
理论上,一个线程甚至可以进行两次操作,而第二个线程将会休眠。
如果您希望两个线程一个接一个地执行,请使用wait-notify机制:
<强>生产者强>
Object lock = LockClass.getLock();
synchronized(lock){
q.put(i);
lock.notifyAll();
lock.wait();
}
<强>消费者强>
Object lock = LockClass.getLock();
synchronized(lock){
q.get(i);
lock.notifyAll();
lock.wait();
}