通知另一个Object中的线程

时间:2014-10-27 07:04:12

标签: java multithreading wait producer-consumer notify

如何在不使用以下生产者和消费者问题中的同步方法的情况下,在以下程序中将线程从一个对象通知给另一个对象。

我在queueput方法中使用get类,并在wait()方法notify()中使用run()Producer {1}}类和Consumer类。

我的目标是使用wait()类和notify()类中的ProducerConsumer方法,而不是在Queue类中使用它们。< / p>

提供IllegalMonitorStateException

程序:

package threads;

class Queue{
    int num;

    int get(int number)
    {

        System.out.println("The Consumer "+number+" got "+num);
        return num;
    }

    void put(int n,int number)
    {

        this.num=n;
        System.out.println("The producer "+number+" put "+this.num);

    }
}

public class producerandconsumer{
    boolean flag=false;
class Producer implements Runnable{
    Queue q;
    int number;
    Producer(Queue q,int number)
    {
        this.q=q;
        this.number = number;
        new Thread(this,"Producer").start();
    }

    public void run()
    {
        for(int i=0;i<10;i++)
        {
            while(flag)
                try{
                    wait();
                }
                catch(InterruptedException e){
                    System.out.println("InterruptedException caught ");
                }
            q.put(i,number);
            flag=true;
            notify();
        }
    }

}

class Consumer implements Runnable{
    Queue q;
    int number;
    Consumer(Queue q,int number)
    {
        this.q=q;
        this.number=number;
        new Thread(this,"Consumer").start();
    }

    public void run()
    {
        for(int i=0;i<10;i++)
        {
            while(!flag)
                try{
                    wait();
                    }
                    catch(InterruptedException e){
                        System.out.println("InterruptedException caught ");
                    }
                flag=false;
                notify();
                q.get(number);
        }
    }
}



public static void main(String[] args) {
    // TODO Auto-generated method stub
    producerandconsumer pc= new producerandconsumer();
    Queue q=new Queue();
    pc.new Producer(q,1);
    pc.new Consumer(q,1);


}

}

该计划的输出:它提供IllegalMonitorStateException

 The producer 1 put 0 Exception in thread "Producer" 
 java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at threads.producerandconsumer$Producer.run(producerandconsumer.java:48)
at java.lang.Thread.run(Unknown Source)

Exception in thread "Consumer" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at threads.producerandconsumer$Consumer.run(producerandconsumer.java:76)
at java.lang.Thread.run(Unknown Source)

2 个答案:

答案 0 :(得分:3)

必须在wait块内调用方法notifysynchronized。这就是你获得illegelMonitorStateException的原因。

答案 1 :(得分:2)

线程之间共享的状态是您的Queue类,因此您必须通过使用适当的同步使其成为线程安全的。将同步代码放在ProducerConsumer中并不是一个好主意,因为这需要在它们之间进行额外的通信,并且不能扩展。

下面是一个简单的同步整数队列示例,它只能容纳一个int(类似于您的Queue)。它会在空队列上调用take时阻塞,并且在队列中调用put时会阻塞。

请注意,您应该使用现有的同步数据结构,例如BlockingQueue的实现,以用于实际应用程序!

public class IntQueue {
    int data;
    boolean filled = false;

    public synchronized int take() throws InterruptedException
    {
        while (!filled) { // wait for filled condition
            wait();
        }

        filled = false; // set not-filled condition
        notifyAll(); // notify (other) waiting threads

        return data;
    }

    public synchronized void put(int data) throws InterruptedException
    {
        while (filled) { // wait for not-filled condition
            wait();
        }

        filled = true; // set filled condition
        notifyAll(); // notify (other) waiting threads

        this.data = data;
    }
}

使用此队列,您可以拥有任意数量的不需要进一步同步的生产者和消费者:

static final IntQueue queue = new IntQueue();
static final int POISON_PILL = -1; // stops Consumer

class Producer implements Runnable {
    public void run() {
        try {
            for(int i = 0; i < 100; i++) {
                System.out.println("producing " + i);
                queue.put(i);
            }
        } catch (InterruptedException ex) { /* done */ }
    }
}

class Consumer implements Runnable {
    public void run() {
        try {
            int n = queue.take();
            // poison pill causes Consumer to stop
            while (n != POISON_PILL) {
                System.out.println("consuming " + i);
                n = queue.take();
            }
        } catch (InterruptedException ex) { /* done */ }
    }
}

public static void main() throws Exception {
    // create threads
    Thread p1 = new Thread(new Producer());
    Thread p2 = new Thread(new Producer());
    Thread c = new Thread(new Consumer());

    // start threads
    p1.start();
    p2.start();
    c.start();

    // wait for producers to complete
    p1.join();
    p2.join();

    // queue poison pill to stop consumer
    queue.put(POISON_PILL);

    // wait for consumer to complete
    c.join();
}