несколько вопросов о синхронизации потоков - PullRequest
0 голосов
/ 15 июня 2011
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");
    }

}

У меня 2 вопроса.

Q1.теперь определение функции wait () выглядит следующим образом: говорит вызывающему потоку отказаться от монитора и перейти в спящий режим, пока какой-то другой поток не войдет в тот же монитор и не вызовет notify ().Теперь в этой программе два потока (один относится к потребителю, а другой к производителю) используют один и тот же объект q в get и put соответственно.Таким образом, существует только один монитор для объекта q, который вводится, когда какой-либо поток использует функцию, включающую q?

Q2. Здесь Потребитель ждет, пока Производитель не уведомит об этом, но Производитель также ждет, пока потребитель не уведомит его?Кто начинает первым?В выводе сначала появляется Producer, но как?

Ответы [ 3 ]

1 голос
/ 15 июня 2011
  1. Q имеет только один монитор
  2. Продюсер запускается первым, потому что вы сначала вызвали его конструктор в своем Main.
0 голосов
/ 15 июня 2011
  1. Каждый объект (экземпляр) в jvm имеет ровно один монитор. Это крайне важно для достижения намеченного поведения (то есть обеспечения того, чтобы только один поток из группы потоков шел вперед, а другие ожидали).

    Вы можете визуализировать замок как своего рода токен / пропуск, необходимый для входа в комнату. Многие больницы используют такую ​​схему, чтобы гарантировать, что с конкретным пациентом может быть только один обслуживающий персонал. Если вы хотите занять место текущего сопровождающего, вы должны wait(), чтобы текущий присутствующий вышел и передал вам пропуск. Только тогда вы можете пройти через охрану, чтобы войти в запретную зону. Конечно, эта схема работает, только если есть только один токен / проход на пациента. В противном случае сотрудники службы безопасности не смогут узнать, у какого пациента уже есть дежурный.

  2. С вашим кодом сначала будет запущен поток производителя, потому что вы создаете производителя раньше потребителя. Но если вы хотите знать, какой из get() или put() будет вызван первым, тогда нет гарантии заказа. На практике вы обычно видите, что put() вызывается первым, потому что поток производителя был запущен первым. Но теоретически остается возможность увидеть get(), названного первым. Это возможно, потому что планировщик потока может отключить поток производителя до того, как он достигнет вызова put ().

0 голосов
/ 15 июня 2011

О втором вопросе: когда ваша программа запускается, объект Q «пуст», что означает, что нет объекта, который мог бы получить потребитель.Таким образом, потребитель должен ждать, пока производитель что-то вставит. Это означает, что производитель сначала напечатает свой «Put», затем потребитель может извлечь его и напечатать свой «Get».

С другой стороны, еслипроизводитель пытается снова что-то поместить до того, как потребитель вынул предыдущий элемент из очереди, производитель должен ждать, пока он не будет взят.

Это означает, что вы получите чередующиеся выходные данные "Put" и "Get"(при условии, что выходной поток не выполняет некоторое переупорядочение).

Это немного отличается от SynchronousQueue тем, что здесь производитель может продолжить работу, если очередь ранее была пустой (и потребитель может продолжить работу, если она была заполнена ранее).), тогда как для SynchronousQueue он будет ждать, пока потребитель не будет готов принять его (что означает, что put и get всегда перекрываются во времени и не могут быть вызваны в одном потоке).

Ваша очередь больше похожа на ArrayBlockingQueue с емкостью 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...