Java 我的线程赢了';别醒来

Java 我的线程赢了';别醒来,java,multithreading,Java,Multithreading,编辑:从答案中添加解决方案 所以我构建了一个经典的多线程程序,其中两个线程,一个生产者和消费者从同一个列表中读取数据。我让我的消费者线程不断地对列表进行投票,这确实起到了作用,但这是低效的,并给我带来了一些其他问题。所以我想我应该试试等待并通知。我的两个线程在下面的代码中使用相同的缓冲区引用: 缓冲区: 我想做的是,每次生产者线程添加一个元素时,它都应该通知我的消费者线程它现在可以从缓冲区读取了。问题是,在添加所有数据之前,它不会被唤醒。这是我从控制台得到的结果: buffer initiate

编辑:从答案中添加解决方案

所以我构建了一个经典的多线程程序,其中两个线程,一个生产者和消费者从同一个列表中读取数据。我让我的消费者线程不断地对列表进行投票,这确实起到了作用,但这是低效的,并给我带来了一些其他问题。所以我想我应该试试等待并通知。我的两个线程在下面的代码中使用相同的缓冲区引用:

缓冲区:

我想做的是,每次生产者线程添加一个元素时,它都应该通知我的消费者线程它现在可以从缓冲区读取了。问题是,在添加所有数据之前,它不会被唤醒。这是我从控制台得到的结果:

buffer initiated
producer started
consumer started
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Adding--------- data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Reading data
Queue is empty 

现在,我真正想要的是:“添加数据”、“读取数据”、“添加数据”等等。

您应该在共享对象上同步(在缓冲区上调用wait和notify)

检查下面的代码-

class Producer implements Runnable {

    private Buffer buffer;
    private String input;

    public Producer(Buffer buffer, String input) {
        this.buffer = buffer;
        this.input = input;
    }

    @Override
    public void run() {
        System.out.println("producer started");
        char[] array = input.toCharArray();
        synchronized (buffer) {
            if (array.length > 0) {
                for (int i = 0; i < array.length; i++) {

                    buffer.addChar(array[i]);
                    System.out.println("Adding--------- data");
                }
                buffer.notifyAll();

            } else {
                try {
                    System.out.println("producer waiting");
                    buffer.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            buffer.notifyAll();
        }
    }
}

class Consumer implements Runnable {
    private Buffer buffer;

    public Consumer(Buffer buffer) {
        this.buffer = buffer;
    }

    @Override
    public void run() {
        System.out.println("consumer started");
        synchronized (buffer) {
            while (buffer.isEmpty()) {
                System.out.println("consumer waiting");
                try {
                    buffer.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            while (!buffer.isEmpty()) {
                System.out.println(buffer.readChar());
            }
            buffer.notifyAll();
        }
    }
}
类生成器实现可运行{
专用缓冲区;
私有字符串输入;
公共生产者(缓冲区、字符串输入){
this.buffer=缓冲区;
这个输入=输入;
}
@凌驾
公开募捐{
System.out.println(“生产商启动”);
char[]数组=input.toCharArray();
已同步(缓冲区){
如果(array.length>0){
for(int i=0;i
同步的
块与您希望
等待的
通知的
对象一起使用。只需将
synchronized
关键字放在方法签名中,您就可以锁定
这个
(当前对象),但当您调用
wait
notify
时,需要
buffer
上的
synchronized

您应该如下所示将方法块放入其中,并从methid签名中删除
synchronized
关键字

synchronized (buffer) {
    // call notify ,( prefer notifyAll.) on buffer
}
和类似的块等待

以下是您可以尝试的更改

public class Producer implements Runnable {
    private Buffer buffer;
    private Callback callback;
    private String input;

    public Producer(Callback callback, Buffer buffer, String input) {
        this.callback = callback;
        this.buffer = buffer;
        this.input = input;
    }

    @Override
    public void run() {
        synchronized (buffer) {
            char[] array = input.toCharArray();
            try {
                for (int i = 0; i < array.length; i++) {
                    buffer.addChar(array[i]);   // production done, 
                    // 1. now notify the consumer thread and 
                    // 2. wait till consumer consumes and notifies.
                    System.out.println("Adding--------- data");
                    callback.returnData("Added " + array[i]);
                    buffer.notifyAll();         // 1. notify done [ consumer notified , this will make consumer get awake from wait state and try to re aquire the lock]
                    buffer.wait();          //2. waiting for notification from consumer thread.
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Consumer implements Runnable {

    private Callback callback;
    private Buffer buffer;

    public Consumer(Callback callback, Buffer buffer) {
        this.callback = callback;
        this.buffer = buffer;
    }

    @Override
    public void run() {
        try { // having try catch outside will enable you to call interrupt on
                // the Thread to stop it
            synchronized (buffer) {
                // though we check for interrupt flag but in case thread is
                // interrupted while waiting, and InterruptedException is
                // thrown, the flag will be cleared, hence we need to put try
                // catch block outside, other option is to put it inside and make thread true again from catch block.
                while (!Thread.currentThread().isInterrupted()) {
                    if (!buffer.isEmpty()) { 
                        System.out.println("Reading data");
                        callback.returnData(" Retrieved " + String.valueOf(buffer.readChar())); // consumption done, now
                                                                                                // 1. Notify the consumer thread
                                                                                                // 2. Wait till more production is done
                        buffer.notifyAll(); // 1. Consumer thread will get this notification and it will get in awakened state. It will try to aquire the lock on Buffer object.
                    } else {
                        System.out.println("Queue is empty ");
                        callback.returnData("Waiting");
                    }
                    buffer.wait();      // 2. wait until more production is done and producer notifies after production
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
公共类生成器实现可运行{
专用缓冲区;
私有回调;
私有字符串输入;
公共生产者(回调、缓冲区、字符串输入){
this.callback=回调;
this.buffer=缓冲区;
这个输入=输入;
}
@凌驾
公开募捐{
已同步(缓冲区){
char[]数组=input.toCharArray();
试一试{
for(int i=0;iclass Producer implements Runnable {

    private Buffer buffer;
    private String input;

    public Producer(Buffer buffer, String input) {
        this.buffer = buffer;
        this.input = input;
    }

    @Override
    public void run() {
        System.out.println("producer started");
        char[] array = input.toCharArray();
        synchronized (buffer) {
            if (array.length > 0) {
                for (int i = 0; i < array.length; i++) {

                    buffer.addChar(array[i]);
                    System.out.println("Adding--------- data");
                }
                buffer.notifyAll();

            } else {
                try {
                    System.out.println("producer waiting");
                    buffer.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            buffer.notifyAll();
        }
    }
}

class Consumer implements Runnable {
    private Buffer buffer;

    public Consumer(Buffer buffer) {
        this.buffer = buffer;
    }

    @Override
    public void run() {
        System.out.println("consumer started");
        synchronized (buffer) {
            while (buffer.isEmpty()) {
                System.out.println("consumer waiting");
                try {
                    buffer.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            while (!buffer.isEmpty()) {
                System.out.println(buffer.readChar());
            }
            buffer.notifyAll();
        }
    }
}
synchronized (buffer) {
    // call notify ,( prefer notifyAll.) on buffer
}
public class Producer implements Runnable {
    private Buffer buffer;
    private Callback callback;
    private String input;

    public Producer(Callback callback, Buffer buffer, String input) {
        this.callback = callback;
        this.buffer = buffer;
        this.input = input;
    }

    @Override
    public void run() {
        synchronized (buffer) {
            char[] array = input.toCharArray();
            try {
                for (int i = 0; i < array.length; i++) {
                    buffer.addChar(array[i]);   // production done, 
                    // 1. now notify the consumer thread and 
                    // 2. wait till consumer consumes and notifies.
                    System.out.println("Adding--------- data");
                    callback.returnData("Added " + array[i]);
                    buffer.notifyAll();         // 1. notify done [ consumer notified , this will make consumer get awake from wait state and try to re aquire the lock]
                    buffer.wait();          //2. waiting for notification from consumer thread.
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Consumer implements Runnable {

    private Callback callback;
    private Buffer buffer;

    public Consumer(Callback callback, Buffer buffer) {
        this.callback = callback;
        this.buffer = buffer;
    }

    @Override
    public void run() {
        try { // having try catch outside will enable you to call interrupt on
                // the Thread to stop it
            synchronized (buffer) {
                // though we check for interrupt flag but in case thread is
                // interrupted while waiting, and InterruptedException is
                // thrown, the flag will be cleared, hence we need to put try
                // catch block outside, other option is to put it inside and make thread true again from catch block.
                while (!Thread.currentThread().isInterrupted()) {
                    if (!buffer.isEmpty()) { 
                        System.out.println("Reading data");
                        callback.returnData(" Retrieved " + String.valueOf(buffer.readChar())); // consumption done, now
                                                                                                // 1. Notify the consumer thread
                                                                                                // 2. Wait till more production is done
                        buffer.notifyAll(); // 1. Consumer thread will get this notification and it will get in awakened state. It will try to aquire the lock on Buffer object.
                    } else {
                        System.out.println("Queue is empty ");
                        callback.returnData("Waiting");
                    }
                    buffer.wait();      // 2. wait until more production is done and producer notifies after production
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}