关于线程同步的一些问题

时间:2011-06-15 11:41:36

标签: java concurrency synchronization

class Q {
int n;
boolean sse = false;
synchronized int get(){
    while (!sse)
        try{
            wait();
        }catch(InterruptedException e){
            System.out.println("Interrupted Exception Caught");
        }
    System.out.println("Got :" + n);
    sse = false;
    notify();
    return n;
        }
synchronized void put(int n){
    while(sse)
        try{
            wait();
        }catch(InterruptedException e){
         System.out.println("Caught");
        }
    this.n = n;
    sse = true;
    System.out.println("Put :" + n);
    notify();
}

}
class Producer implements Runnable{
    Q q;
    Producer(Q q) {
        this.q = q;
        new Thread(this, "Prodcuer").start();
    }
    public void run(){
        int i = 0;
        while(true) {
        q.put(i++);
        }
    }
}
class Consumer implements Runnable{
    Q q;
    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    public void run(){

        while(true) {
        q.get();
        }
    }
}
public class Main {


    public static void main(String[] args) {
  Q q = new Q();
  new Producer(q);
  new Consumer(q);
  System.out.println("Press Control C to stop");
    }

}

我有两个问题。

Q1。现在wait()函数的定义是这样的:告诉调用线程放弃监视器并进入休眠状态,直到某个其他线程进入同一个监视器并调用notify()。 现在在这个程序中,两个线程(一个与消费者相关,一个与生产者相关)分别在get和put中使用相同的对象q。那么对象q是否只存在一个监视器,当任何线程使用涉及q?

的函数时输入该监视器

Q2在这里,消费者等到生产者通知它,但生产者还等到消费者通知它?谁首先开始? 在输出中,Producer首先出现但是如何?

3 个答案:

答案 0 :(得分:1)

  1. Q只有一台显示器
  2. 生产者首先启动,因为您首先在Main中调用了它的构造函数。

答案 1 :(得分:0)

关于第二个问题:当程序启动时,Q对象“为空”,这意味着消费者无法得到任何对象。因此,消费者必须等到生产者放入内容。这意味着生产者将首先打印其“Put”,然后消费者可以检索它并打印其“获取”。

另一方面,如果生产者试图在消费者将前一个元素从队列中取出之前再次放置一些东西,那么生产者必须等到它被拿走。

这意味着您将获得交替的“Put”和“Get”输出(假设输出流不进行某些重新排序)。

这与SynchronousQueue略有不同,因为如果队列之前是空的,那么生产者可以继续(如果之前的消费者可以继续,那么生产者可以继续),而对于SynchronousQueue,它会等到消费者准备就绪接受它(这意味着putget 总是在时间上重叠,并且不能在同一个线程上调用。)

您的队列更类似于容量为1的ArrayBlockingQueue。

答案 2 :(得分:0)

  1. jvm中的每个对象(实例)都只有一个监视器。这对于实现预期的行为是至关重要的(即确保只有一个线程中的一个线程继续前进而其他线程等待)。

    您可以将锁可视化为进入房间所需的一种令牌/通行证。许多医院采用这样的方案来确保只有一名服务员可以与特定患者在一起。如果您想取代现任服务员,您应该wait()让当前服务员出来并将通行证交给您。只有这样你才能通过安检进入禁区。当然,只有每位患者只有一个令牌/通行证时,此方案才有效。否则,保安人员无法知道哪位病人已经有服务员。

  2. 使用您的代码,生产者线程将首先启动,因为您在使用者之前创建生产者。但是,如果您想知道首先调用get()put()中的哪一个,则无法保证订单。在实践中,您通常会看到首先调用put()因为首先启动了生产者线程。但理论上仍然有可能首先看到get()。这是可能的,因为线程调度程序可能在它到达put()调用之前切换出生产者线程。