#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. И это не «двойная» проверка, потому что вы просто проверяете. Если вы на самом деле посмотрите, что такое блокировка с двойной проверкой , вы увидите, что вы на самом деле проверяете условие дважды на блок (а не просто зацикливаете), и, что важно, вы можете получить блокировку . Считаете ли вы это «тройной проверкой», если вы дважды спали перед созданием / потреблением?