2016-02-22 3 views
-3

Я написал код для проблемы с производителем-потребителем, где производитель производит товар три раза, а затем потребитель потребляет товар один раз. Приведенный ниже код работает нормально как требование, но основной поток не остановится. Я не знаю, почему это не остановится, я не могу поймать. Не могли бы вы, пожалуйста, взглянуть в нижнем коде и исправить?Проблемы с потребителями-производителями с использованием java-потоков

public class ProducerConsumerProblem 
{ 

    public static void main(String[] args) 
    { 

    ProducerConsumerStack st = new ProducerConsumerStack(); 
    new ProducerThread(st); 
    new ConsumerThread(st); 

    } 
} 

class ProducerConsumerStack 
{ 
    int x; 
    boolean flag = false; 
    int producedCount = 0; 

    public synchronized void push(int x) 
    { 
    if (flag) 
    { // flag==true 
     try 
     { 
     wait(); 
     } 
     catch (Exception e) 
     { 
     System.out.println(e); 
     } 
    } 
    this.x = x; 
    System.out.println(x + " is produced.."); 
    try 
    { 
     Thread.sleep(250); 
    } 
    catch (Exception e) 
    { 
     System.out.println(e); 
    } 

    this.producedCount++; 
    if (this.producedCount == 3) 
    { 
     this.producedCount = 0; 
     this.flag = true; 
     notifyAll(); 
    } 

    } 

    synchronized public void pop() 
    { 
    if (!flag) 
    { // flag==false 
     try 
     { 
     wait(); 
     } 
     catch (Exception e) 
     { 
     System.out.println(e); 
     } 
    } 
    System.out.println(x + " is consumed.\n"); 
    try 
    { 
     Thread.sleep(1500); 
    } 
    catch (Exception e) 
    { 
     System.out.println(e); 
    } 
    flag = false; 
    notify(); 
    } 
} 

class ProducerThread implements Runnable 
{ 
    ProducerConsumerStack st = null; 

    ProducerThread(ProducerConsumerStack st) 
    { 
    this.st = st; 
    Thread t1 = new Thread(this); 
    t1.start(); 
    } 

    public void run() 
    { 
    int a = 1; 
    for (int i = 0; i < 15; i++) 
    { 
     st.push(a++); 
    } 
    } 
} 

class ConsumerThread implements Runnable 
{ 
    ProducerConsumerStack st = null; 

    ConsumerThread(ProducerConsumerStack st) 
    { 
    this.st = st; 
    Thread t2 = new Thread(this); 
    t2.start(); 
    } 

    public void run() 
    { 
    for (int i = 0; i < 15; i++) 
    { 
     st.pop(); 
    } 
    } 
} 
+0

Я не знаю, почему вы говорите: «основная нить не остановится». Основная() процедура в вашей программе создает три объекта, а затем выходит. Что вы действительно пытаетесь спросить? –

+0

P.S., я вижу потенциальную проблему в вашем коде: там, где конструктор объекта выполняет 'new Thread (this) .start();'. Передача 'this' в другой поток в конструкторе потенциально позволяет новому потоку обращаться к объекту в неинициализированном/не полностью инициализированном состоянии. –

+0

@james large: Пожалуйста, запустите тот же код, а затем посмотрите, завершается ли основная нить или нет. Это совсем не конец. –

ответ

0

@james большой: Пожалуйста, запустите тот же код, а затем посмотреть, является ли основной поток отделки или нет. Это совсем не конец.

Я побежал программу с одним небольшим изменением: Я добавил поток, который ждет в основной поток, чтобы умереть, а затем выводит сообщение: «! Спокойной ночи»

public class ProducerConsumerProblem 
{ 
    static volatile Thread mainThread; 
    public static void main(String[] args) 
    { 
     mainThread = Thread.currentThread(); 
     ProducerConsumerStack st = new ProducerConsumerStack(); 
     new ProducerThread(st); 
     new ConsumerThread(st); 

     new Thread(() -> { 
      try { 
       mainThread.join(); 
      } catch (Exception ex) { 
       System.out.println("Aaaaaaaugh!"); 
      } 
      System.out.println("Nighty Night!"); 
     }).start(); 

    } 
} 

напечатанное, доказав, что основная нить сделала на самом деле умереть.

нить, которая не прекращает была потребительской нити: К тому времени, когда производитель нить обозвал st.push() пятнадцать раз, потребитель тред только завершил пять вызовов st.pop(), и он застрял в шесте вызова, ожидая уведомление, которое никогда не произойдет.


Возможно, вы захотите ознакомиться со своим классом ProducerConsumerStack. Вы помещаете «стек» в свое имя, но для меня это не похоже на стек. Во-первых, стек должен иметь возможность хранить более одного элемента. Ваш может хранить только один.

+0

Привет, не могли бы вы преобразовать свой код с помощью ниже java8-версии, здесь вы используете выражение лямбда, которое является функцией java8, я не работаю в java8, а также у меня нет идеи о лямбда-выражении. Преобразуйте его в java6. –

+0

@ManishKumar Лямбда в моем примере - это просто сокращенный способ создания нового объекта Runnable. Аргумент конструктора 'Thread' _must_ будет« Runnable ». Компилятор знает это, поэтому он автоматически создает анонимный класс, который «реализует Runnable». И поскольку интерфейс 'Runnable' определяет только один метод' run() ', компилятор знает, что тело лямбда должно быть предназначено как тело этого метода. Lambdas и функциональные интерфейсы могут показаться немного странными вначале, но на самом деле они довольно простые, как только вы привыкнете к идее. –

Смежные вопросы