2013-08-13 3 views
4

Я хочу написать программу с использованием многопоточных методов ожидания и уведомления в Java.
Эта программа имеет стек (max-length = 5). Производитель генерирует число навсегда и помещает его в стек, а потребитель выбирает его из стека.

Когда стек является полным, продюсер должен ждать, и когда стек пуст, потребители должны подождать.
Проблема в том, что она работает только один раз, я имею в виду, что когда она производит 5 номеров, она останавливается, но я помещаю методы запуска в то время как (истинный) блок работает без перехвата, но это не так.
Вот что я пробовал до сих пор.
класс Производитель:производитель - потребитель многопоточность в Java

package trail; 
import java.util.Random; 
import java.util.Stack; 

public class Thread1 implements Runnable { 
    int result; 
    Random rand = new Random(); 
    Stack<Integer> A = new Stack<>(); 

    public Thread1(Stack<Integer> A) { 
     this.A = A; 
    } 

    public synchronized void produce() 
    { 
     while (A.size() >= 5) { 
      System.out.println("List is Full"); 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     result = rand.nextInt(10); 

     System.out.println(result + " produced "); 
     A.push(result); 
     System.out.println(A); 

     this.notify(); 
    } 

    @Override 
    public void run() { 
     System.out.println("Producer get started"); 

     try { 
      Thread.sleep(10); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     while (true) { 
      produce(); 
      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

И потребитель:

package trail; 

import java.util.Stack; 

public class Thread2 implements Runnable { 
    Stack<Integer> A = new Stack<>(); 

    public Thread2(Stack<Integer> A) { 
     this.A = A; 
    } 

    public synchronized void consume() { 
     while (A.isEmpty()) { 
      System.err.println("List is empty" + A + A.size()); 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     System.err.println(A.pop() + " Consumed " + A); 
     this.notify(); 
    } 

    @Override 
    public void run() { 
     System.out.println("New consumer get started"); 
     try { 
      Thread.sleep(10); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     while (true) { 
      consume(); 
     } 
    } 
} 

и здесь является основным методом:

public static void main(String[] args) { 

     Stack<Integer> stack = new Stack<>(); 

     Thread1 thread1 = new Thread1(stack);// p 
     Thread2 thread2 = new Thread2(stack);// c 
     Thread A = new Thread(thread1); 
     Thread B = new Thread(thread2); 
     Thread C = new Thread(thread2); 
     A.start(); 

     B.start(); 
     C.start();  
    } 
+0

Какой объект вы синхронизируете в продюсере? На каком объекте вы синхронизируете пользователя? –

+0

, пожалуйста, заполните код и удалите пустые строки и те, у которых есть бесполезные комментарии. –

+0

метод prodeuce в классе Thread1 и метод потребления в Thread2-классе синхронизированы. –

ответ

-1

Похоже, вы пропустили что-то о wait(), notify() и synchronized. См. this example, он должен вам помочь.

2

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

Также не инициализируйте стек в ваших классах нитей, так как вы передаете их в конструкторе из основного класса, поэтому нет необходимости в этом.

Всегда старайтесь избегать маркировки любого метода с синхронизированным ключевым словом, а не пытаться поставить критический раздел кода в синхронизированном блоке, потому что чем больше размер вашей синхронизированной области больше повлияет на производительность.

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

Производитель Код:

public void produce() { 
    synchronized (A) { 
     while (A.size() >= 5) { 
      System.out.println("List is Full"); 
      try { 
       A.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     result = rand.nextInt(10); 

     System.out.println(result + " produced "); 
     A.push(result); 
     System.out.println("stack ---"+A); 

     A.notifyAll(); 
    } 
} 

Потребительское Код:

public void consume() { 
    synchronized (A) { 
     while (A.isEmpty()) { 
      System.err.println("List is empty" + A + A.size()); 
      try { 
       System.err.println("wait"); 
       A.wait(); 

      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     System.err.println(A.pop() + " Consumed " + A); 
     A.notifyAll(); 
    } 
} 
+0

Что делает A.notifyAll() действительно? –

+0

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

+0

Почему мы используем цикл while, а не если? Любые конкретные причины для этого? –

2

Ваш потребитель и вы производитель синхронизированы на различных объектов и не блокируют друг друга. Если это сработает, я полагаю, что это случайно.

Читайте также: java.util.concurrent.BlockingQueue и java.util.concurrent.ArrayBlockingQueue. Они предоставляют вам более современный и простой способ реализации этого шаблона.

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

+0

Где я могу найти полезную статью? –

+0

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html – Bex

2

Я думаю, что это будет лучше для понимания и работы с синхронизацией в общем, если вы пытаетесь выделить три вещи, которые в настоящее время неоднозначны:

  1. Задача, которая собирается сделать фактическое работа. Имена для классов Thread1 & Thread2 вводят в заблуждение.Они не являются объектами Thread, но на самом деле это задания или задачи, реализующие интерфейс Runnable, который вы передаете объектам Thread.

  2. сам объект Thread, который вы создаете в главном

  3. Общий объект, который инкапсулирует синхронизированные операции/логику очереди, стек и т.д. Этот объект будет разделена между задачами. И внутри этого общего объекта вы будете заниматься операциями добавления/удаления (либо с синхронизированными блоками, либо с синхронизированными методами). В настоящее время (как уже указывалось) синхронизация выполняется по самой задаче (т. Е. Каждая задача ждет и уведомляет о своей собственной блокировке и ничего не происходит). Когда вы разделяете проблемы, то есть пусть один класс правильно справится, в конечном итоге станет ясно, где проблема.

0

Вы можете использовать удивительный пакет Java java.util.concurrent и его классы.

Вы можете легко реализовать проблему потребительского потребления, используя BlockingQueue. A BlockingQueue уже поддерживает операции, которые ждут , чтобы очередь стала непустой при извлечении элемента и подождала , чтобы пространство стало доступным в очереди при хранении элемента.

Без BlockingQueue, каждый раз, когда мы помещаем данные в очередь на стороне производителя , нам нужно проверить, если очередь заполнена, а если полная, подождать некоторое время , проверьте еще раз и продолжить. Точно так же на стороне потребителя нам нужно будет проверить, пустует ли очередь, и если пусто, подождите некоторое время , повторите проверку и продолжите. Однако с BlockingQueue нам не нужно написать дополнительную логику, чем просто добавить данные от производителя и данные опроса от Consumer.

Подробнее От:

http://javawithswaranga.blogspot.in/2012/05/solving-producer-consumer-problem-in.html

http://www.javajee.com/producer-consumer-problem-in-java-using-blockingqueue

2

Попробуйте это:

import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class CircularArrayQueue<T> { 

    private volatile Lock rwLock = new ReentrantLock(); 
    private volatile Condition emptyCond = rwLock.newCondition(); 
    private volatile Condition fullCond = rwLock.newCondition(); 

    private final int size; 

    private final Object[] buffer; 
    private volatile int front; 
    private volatile int rare; 

    /** 
    * @param size 
    */ 
    public CircularArrayQueue(int size) { 
     this.size = size; 
     this.buffer = new Object[size]; 
     this.front = -1; 
     this.rare = -1; 
    } 

    public boolean isEmpty(){ 
     return front == -1; 
    } 

    public boolean isFull(){ 
     return (front == 0 && rare == size-1) || (front == rare + 1); 
    } 

    public void enqueue(T item){ 
     try { 
      // get a write lock 
      rwLock.lock(); 
      // if the Q is full, wait the write lock 
      if(isFull()) 
       fullCond.await(); 

      if(rare == -1){ 
       rare = 0; 
       front = 0; 
      } else if(rare == size - 1){ 
       rare = 0; 
      } else { 
       rare ++; 
      } 

      buffer[rare] = item; 
      //System.out.println("Added\t: " + item); 

      // notify the reader 
      emptyCond.signal(); 
     } catch(InterruptedException e){ 
      e.printStackTrace(); 
     } finally { 
      // unlock the write lock 
      rwLock.unlock(); 
     } 

    } 

    public T dequeue(){ 
     T item = null; 
     try{ 
      // get the read lock 
      rwLock.lock(); 
      // if the Q is empty, wait the read lock 
      if(isEmpty()) 
       emptyCond.await(); 

      item = (T)buffer[front]; 
      //System.out.println("Deleted\t: " + item); 
      if(front == rare){ 
       front = rare = -1; 
      } else if(front == size - 1){ 
       front = 0; 
      } else { 
       front ++; 
      } 

      // notify the writer 
      fullCond.signal(); 

     } catch (InterruptedException e){ 
      e.printStackTrace(); 
     } finally{ 
      // unlock read lock 
      rwLock.unlock(); 
     } 
     return item; 
    } 
} 
0
package javaapplication; 

import java.util.Stack; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

public class ProducerConsumer { 

    public static Object lock = new Object(); 
    public static Stack stack = new Stack(); 

    public static void main(String[] args) { 
     Thread producer = new Thread(new Runnable() { 
      int i = 0; 

      @Override 
      public void run() { 
       do { 
        synchronized (lock) { 

         while (stack.size() >= 5) { 
          try { 
           lock.wait(); 
          } catch (InterruptedException e) { 
          } 
         } 
         stack.push(++i); 
         if (stack.size() >= 5) { 
          System.out.println("Released lock by producer"); 
          lock.notify(); 
         } 
        } 
       } while (true); 

      } 

     }); 

     Thread consumer = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       do { 
        synchronized (lock) { 
         while (stack.empty()) { 
          try { 
           lock.wait(); 
          } catch (InterruptedException ex) { 
           Logger.getLogger(ProdCons1.class.getName()).log(Level.SEVERE, null, ex); 
          } 
         } 

         while(!stack.isEmpty()){ 
          System.out.println("stack : " + stack.pop()); 
         } 

         lock.notifyAll(); 
        } 
       } while (true); 
      } 
     }); 

     producer.start(); 

     consumer.start(); 

    } 

} 
0

Посмотрите на этом примере кода:

import java.util.concurrent.*; 
import java.util.Random; 

public class ProducerConsumerMulti { 
    public static void main(String args[]){ 
     BlockingQueue<Integer> sharedQueue = new LinkedBlockingQueue<Integer>(); 

     Thread prodThread = new Thread(new Producer(sharedQueue,1)); 
     Thread consThread1 = new Thread(new Consumer(sharedQueue,1)); 
     Thread consThread2 = new Thread(new Consumer(sharedQueue,2)); 

     prodThread.start(); 
     consThread1.start(); 
     consThread2.start(); 
    } 
} 
class Producer implements Runnable { 
    private final BlockingQueue<Integer> sharedQueue; 
    private int threadNo; 
    private Random rng; 
    public Producer(BlockingQueue<Integer> sharedQueue,int threadNo) { 
     this.threadNo = threadNo; 
     this.sharedQueue = sharedQueue; 
     this.rng = new Random(); 
    } 
    @Override 
    public void run() { 
     while(true){ 
      try { 
       int number = rng.nextInt(100); 
       System.out.println("Produced:" + number + ":by thread:"+ threadNo); 
       sharedQueue.put(number); 
       Thread.sleep(100); 
      } catch (Exception err) { 
       err.printStackTrace(); 
      } 
     } 
    } 
} 

class Consumer implements Runnable{ 
    private final BlockingQueue<Integer> sharedQueue; 
    private int threadNo; 
    public Consumer (BlockingQueue<Integer> sharedQueue,int threadNo) { 
     this.sharedQueue = sharedQueue; 
     this.threadNo = threadNo; 
    } 

    @Override 
    public void run() { 
     while(true){ 
      try { 
       int num = sharedQueue.take(); 
       System.out.println("Consumed: "+ num + ":by thread:"+threadNo); 
       Thread.sleep(100); 
      } catch (Exception err) { 
       err.printStackTrace(); 
      } 
     } 
    } 
} 

Примечания:

  1. Started один Producer и два Consumers как в вашей постановке задачи
  2. Producer будет производить случайные числа от 0 до 100 в бесконечном цикле
  3. Consumer будет потреблять эти числа в бесконечном цикле
  4. Оба Producer и Consumer доля блокировки бесплатно и Потокобезопасная LinkedBlockingQueue который потокобезопасен.Вы можете удалить методы wait() и notify(), если вы используете эти расширенные параллельные конструкции.
Смежные вопросы