Потоки Java — с одним производителем и потребителем, с использованием режима ожидания и продолжения

#java #multithreading #thread-safety #producer-consumer #double-checked-locking

#java #многопоточность #безопасность потоков #производитель-потребитель #дважды проверено -блокировка

Вопрос:

Я пытался решить проблему с одним производителем и потребителем в соответствии с формулировкой проблемы из Википедии https://en.wikipedia.org/wiki/Producer–consumer_problem Производство и потребление должны происходить бесконечно, так что производитель не должен добавлять в очередь, когда она заполнена, а потребитель не должен потреблять, когда она пуста

Я решил это с помощью Thread.sleep и двойной проверки с использованием continue в бесконечном цикле while и создал два потока, один производитель и потребитель, кажется, он работает нормально без сбоев, но я не нашел это решение рекомендованным в другом месте, я приложил код

Мой вопрос в том, сломается ли это решение или у него есть какое-либо снижение производительности по сравнению с блокировкой или использованием количества производства / потребления,

Код:

 import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Random;

class Buffer{

    static final int MAX_SIZE=5;
    static Deque<Integer> bufferQueue=new ArrayDeque<>();


    static int produce(){
        int value=new Random().nextInt(10);
        bufferQueue.offer(value);
        return value;

    }

    static int consume(){
        return bufferQueue.poll();
    }
}
public class BufferTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        //Producer Thread
        new Thread(
                ()->{
                    while(true){

                        if(Buffer.bufferQueue.size()==Buffer.MAX_SIZE){
                            try {
                                System.out.println("Buffer Full");
                                Thread.sleep(2000);
                                continue;    //Double Check
                            } catch (Exception e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }

                        }
                        System.out.println("Produced " Buffer.produce());
                    }
                },"Producer"
                ).start();

        //Consumer Thread
        new Thread(
                ()->{
                    while(true){

                        if(Buffer.bufferQueue.size()==0){
                            try {
                                System.out.println("Buffer Empty");
                                Thread.sleep(2000);
                                continue;   //Double check
                            } catch (Exception e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                        System.out.println("Consumed " Buffer.consume());
                    }
                },"Consumer"
                ).start();
    }

}
  

Комментарии:

1. «есть ли у него какое-либо снижение производительности» Да, вы спите в течение 2 секунд всякий раз, когда список пуст или полон.

2. Помещение continue после режима ожидания на самом деле не является двойной проверкой, и это определенно не блокировка.

3. @Andy: Спасибо за ответ, поток переходит в режим ожидания только тогда, когда очередь заполнена или пуста, что и делается в блокирующей очереди, если я не ошибаюсь, и как вы утверждаете, что использование continue не является двойной проверкой, когда производитель переходит в режим ожидания, когда очередь заполнена, и пробуждает continueоператор заставляет его снова запускать цикл и снова проверять, заполнена ли очередь правильно?

4. «это то, что делается в очереди блокировки, если я не ошибаюсь», вы ошибаетесь. Например, «sleep» не встречается в коде для ArrayBlockingQueue , DelayQueue , и т.д. LinkedBlockingQueue

5. И это не «двойная» проверка, потому что вы просто проверяете. Если вы на самом деле посмотрите, что такое блокировка с двойной проверкой , вы увидите, что вы на самом деле проверяете условие дважды на блок (а не просто зацикливаете), и, что важно, вы можете получить блокировку . Считаете ли вы это «тройной проверкой», если вы дважды спали перед созданием / потреблением?