2013-02-01 30 views
2

我正在写一个小应用程序(比“HelloWorld”稍大一些)。任务是创建一个生产者和几个消费者。生产者生成integeres并将它们放入动态堆栈(这是我的监视器对象),并且消费者试图从堆栈中获取这些整数。 我知道如何使用一个标志创建1个生产者+ 1个消费者,并在里面等待()。但是如何对多个消费者也这样做。使用java线程的多监视器同步

请看看我的代码:

public interface StackQueueIF { 
    void push(int value); 
    int pop(); 
} 

public class DynamicStack implements StackQueueIF{ 

    private volatile int stck[]; 
    private volatile int tos; 

    boolean valueSet = false; 

    public DynamicStack(int size) { 
     stck = new int[size]; 
     tos = -1; 
    } 

    @Override 
    public synchronized void push(int item) { 
     while(valueSet){ 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

     if (tos == stck.length-1) { 
      System.out.println("---------STACK HAS BEEN DOUBLED--------"); 
      int temp[] = new int[stck.length * 2]; 
      for (int i = 0; i < stck.length; i++) temp[i] = stck[i]; 
      stck = temp; 
      stck[++tos] = item; 
     }else 
      stck[++tos] = item; 

     valueSet = true; 
     notifyAll(); 
    } 

    @Override 
    public synchronized int pop() { 
     while(!valueSet){ 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

     valueSet = false; 
     notifyAll(); 
     return stck[tos--]; 
    } 
} 

class Producer implements Runnable{ 
    StackQueueIF queue; 
    String producerName; 
    private static int counter = 0; 

    public Producer(StackQueueIF queue, String name) { 
     this.queue = queue; 
     this.producerName = name; 
     new Thread(this,producerName).start(); 
    } 

    @Override 
    public void run() { 
     while(true){ 
      System.out.println(this.producerName + " puts " + (++counter) 
       + " into stack"); 
      this.queue.push(counter); 
      try { 
       Thread.sleep(500); 
      } catch (InterruptedException e) { 
       System.err.println(producerName + " interrupted"); 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

class Consumer implements Runnable{ 
    StackQueueIF queue; 
    String consumerName; 

    public Consumer(StackQueueIF queue, String consumerName) { 
     this.queue = queue; 
     this.consumerName = consumerName; 
     new Thread(this, this.consumerName).start(); 
    } 

    @Override 
    public void run() { 
     while(true){ 
      System.out.println(this.consumerName + " gets " + queue.pop() + " from stack"); 
      try { 
       Thread.sleep(500); 
      } catch (InterruptedException e) { 
       System.err.println(consumerName + "interrupted"); 
       e.printStackTrace(); 
      } 
     } 
    } 

} 

public class QueueTester { 
    public static void main(String[] args) { 
     StackQueueIF queue = new DynamicStack(10); 
     new Producer(queue,"Producer №1"); 

     new Consumer(queue,"Consumer №1"); 
     new Consumer(queue,"Consumer №2"); 
    } 
} 
+0

如果你运行这段代码,你会看到只有消费者#1变值而消费者#2一无所获。那就是问题所在。他们都应该有机会从堆叠中获得某些东西,或者等待它是空的。 –

+0

+1对于使用№;) –

回答

1

这是我会怎么写堆栈

public interface IntStack { 
    void push(int value); 
    int pop() throws InterruptedException; 
} 

public class DynamicStack implements IntStack { 
    private int size = 0, stack[]; 

    public DynamicStack() { 
     this(16); 
    } 

    public DynamicStack(int capacity) { 
     stack = new int[capacity]; 
    } 

    @Override 
    public synchronized void push(int item) { 
     if (size + 1 == stack.length) 
      stack = Arrays.copyOf(stack, stack.length * 2); 
     stack[size++] = item; 
     notifyAll(); // notify() would also do. 
    } 

    @Override 
    public synchronized int pop() throws InterruptedException { 
     while (size == 0) 
      wait(); 
     return stack[--size]; 
    } 
} 
+0

感谢您的一个良好的cood和援助。 我将睡眠时间改为1 ms,10 000次迭代后,每个线程都有机会运行,但其中一些运行了500次迭代,而其他运行有轻微变化,运行5-10次。我认为这是线程优先级问题和Windows线程实现。 感谢您的帮助。 P.S.我来自乌克兰,所以我在俄罗斯输入评论并忘记更改№标志:-) –

+0

线程同时运行,您无法确定它们的行为方式,除非您在代码中控制它们。注意:因为默认情况下你会有偏见的锁定,这意味着一个线程长时间受到青睐。尝试'-XX:-UseBiasedLocking'注意:通常队列而不是堆栈正在多线程系统中使用。我喜欢你使用№所以不要删除它。 ;) –