简体   繁体   English

同步且线程未按预期工作

[英]Synchronized and threads not working as expected

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. 有一个类Q ,它具有一个称为n的字段,以及两个方法put()get() ,它们设置n的值或检索n的值。 And then there are two classes Producer and Consumer . 然后有两个类ProducerConsumer Producer class has a thread which calls put and consumer class has a thread which calls get . Producer类具有调用put的线程, consumer类具有调用get的线程。 I am trying to synchronize it using an Object lock which is the only instance of Singleton class LockClass. 我试图使用Object lock来同步它,该Object lock是Singleton类LockClass.的唯一实例LockClass.

So, here is my class Q : 所以,这是我的班级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: 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 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);
    }

}

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? 我想念什么吗?

From the doc: 从文档中:

... 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 ...但是,由于这些睡眠时间受到底层操作系统提供的功能的限制,因此不能保证这些睡眠时间的精确度。 在任何情况下,您都不能假设调用sleep会在指定的时间段内暂停线程

https://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html https://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html

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: 来自Thread.sleep Java文档的报价:

[...] 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: 如果希望两个线程一个接一个执行,请使用wait-notify机制:

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();    
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM