同步和线程未按预期工作

Synchronized and threads not working as expected

我正在尝试做这样的事情:

有一个class Q,它有一个名为n的字段和两个方法put()get(),它们设置n的值或检索n 的值。然后有两个 classes ProducerConsumerProducer 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