为什么 Consumer 线程无法从 Vector 中删除消息?

Why Consumer thread is not able to remove messages from Vector?

我正在尝试为生产者/消费者问题创建一个解决方案,其中一个线程将消息放入 Vector 而另一个线程从中删除。

import java.util.Vector;
public class Producer implements Runnable {
    static final int MAXQUEUE = 5;
    private Vector<String> messages;

    public Producer(Vector<String> messages) {
        super();
        this.messages = messages;
    }

    @Override
    public void run() {
        try {
            while (true) 
                putMessage();
        } catch (InterruptedException e) {
        }
    }

    private synchronized void putMessage() throws InterruptedException {
        while (messages.size() == MAXQUEUE) {
            wait();
        }
        messages.addElement(new java.util.Date().toString());
        System.out.println("put message");
        notifyAll();
    }

    public static void main(String args[]) {    
        Vector<String> messages = new Vector<String>();
        new Thread(new Producer(messages)).start();
        new Thread(new Consumer(messages)).start();
    }
}

class Consumer implements Runnable{
    public Consumer(Vector<String> messages) {
        super();
        this.messages = messages;
    }
    private Vector<String> messages;

    public synchronized String getMessage() throws InterruptedException {
        notifyAll();
        while (messages.size() == 0) {
            wait();//By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep.
        }
        String message = (String) messages.firstElement();
        messages.removeElement(message);
        return message;
    }

    @Override
    public void run() {
        try {
            while (true) {
                String message = getMessage();
                System.out.println("Got message: " + message);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

每当我 运行 程序时,它都会打印 put 消息 5 次。即使在 notifyAll() 之后我也不明白,它没有给消费者锁。

登录到控制台非常慢,因此如果您在不持有锁的情况下执行此操作,您就给了消费者一个机会。

@Override
public void run() {
    try {
        while (true) {
            // slows the producer a little to give the consumer a chance to get the lock.
            System.out.println("put message");
            putMessage();
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private void putMessage() throws InterruptedException {
    synchronized  (messages) {
        while (messages.size() == MAXQUEUE) {
            messages.wait();
        }
        messages.addElement(new java.util.Date().toString());
        messages.notifyAll();
    }
}

顺便说一句,消费者可以这样写

public String getMessage() throws InterruptedException {
    synchronized (messages) {
        while (messages.isEmpty()) {
            messages.wait();//By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep.
        }
        messages.notifyAll();
        return messages.remove(0);
    }
}

您的代码无法正常工作,因为您的两个线程未 notifying/waiting 在同一监视器上。

他们每个人都在自己的监视器上通知和等待,而不是共享监视器。更改代码以使用共享监视器,例如messages,包括同步。

private void putMessage() throws InterruptedException {
    synchronized (messages) { // <======
        while (messages.size() == MAXQUEUE) {
            messages.wait();  // <======
        }
        messages.addElement(new java.util.Date().toString());
        System.out.println("put message");
        messages.notifyAll(); // <======
    }
}

public String getMessage() throws InterruptedException {
    synchronized (messages) { // <======
        while (messages.size() == 0) {
            messages.wait();  // <======
        }
        String message = (String) messages.firstElement();
        messages.removeElement(message);
        messages.notifyAll(); // <======
        return message;
    }
}

注意方法不再同步。