同步和线程未按预期工作
Synchronized and threads not working as expected
我正在尝试做这样的事情:
有一个class Q
,它有一个名为n
的字段和两个方法put()
和get()
,它们设置n的值或检索n 的值。然后有两个 classes Producer
和 Consumer
。 Producer
class 有一个调用 put
的线程,consumer
class 有一个调用 get
的线程。我正在尝试使用 Object lock
同步它,这是 Singleton class LockClass.
的唯一实例
所以,这是我的 class 问:
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;
}
}
锁类:
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 : 这个 class 有主要功能
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
所以,我实际上是让线程在生产者和消费者中都处于休眠状态,以便有足够的时间进行上下文切换。现在当两者都需要同时休眠时,如果生产者先休眠,它应该先醒来。但是正如我在输出中看到的那样,生产者先睡觉,但消费者仍然先醒来,因为无论哪个线程先醒来,都应该获得锁,因此另一个线程应该等到锁被释放。
为什么它没有按我预期的方式工作?我错过了什么吗?
不保证睡眠超时是严格的,所以一个线程可以晚睡早醒是绝对有效的。引自 Thread.sleep java 文档:
[...] subject to the precision and accuracy of system timers and schedulers
理论上,一个线程甚至可以执行两次操作,而第二个线程将处于休眠状态。
如果你想让两个线程依次行动,使用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();
}
来自文档:
... However, these sleep times are not guaranteed to be precise, because
they are limited by the facilities provided by the underlying OS... In any case, you cannot assume that invoking sleep
will suspend the thread for precisely the time period specified
https://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html
我正在尝试做这样的事情:
有一个class Q
,它有一个名为n
的字段和两个方法put()
和get()
,它们设置n的值或检索n 的值。然后有两个 classes Producer
和 Consumer
。 Producer
class 有一个调用 put
的线程,consumer
class 有一个调用 get
的线程。我正在尝试使用 Object lock
同步它,这是 Singleton class LockClass.
所以,这是我的 class 问:
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;
}
}
锁类:
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 : 这个 class 有主要功能
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
所以,我实际上是让线程在生产者和消费者中都处于休眠状态,以便有足够的时间进行上下文切换。现在当两者都需要同时休眠时,如果生产者先休眠,它应该先醒来。但是正如我在输出中看到的那样,生产者先睡觉,但消费者仍然先醒来,因为无论哪个线程先醒来,都应该获得锁,因此另一个线程应该等到锁被释放。
为什么它没有按我预期的方式工作?我错过了什么吗?
不保证睡眠超时是严格的,所以一个线程可以晚睡早醒是绝对有效的。引自 Thread.sleep java 文档:
[...] subject to the precision and accuracy of system timers and schedulers
理论上,一个线程甚至可以执行两次操作,而第二个线程将处于休眠状态。
如果你想让两个线程依次行动,使用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();
}
来自文档:
... However, these sleep times are not guaranteed to be precise, because they are limited by the facilities provided by the underlying OS... In any case, you cannot assume that invoking sleep will suspend the thread for precisely the time period specified
https://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html