Я получил пример от here. Но там они просто реализуют этот пример только один за другим. Среднее первое целое число для создания, а затем путайте и останавливайте программу.Продюсер и потребитель, использующий блокировку в Java
Вот оригинальный пример:
class ProducerConsumerImpl {
// producer consumer problem data
private static final int CAPACITY = 10;
private final Queue queue = new LinkedList<>();
private final Random theRandom = new Random();
// lock and condition variables
private final Lock aLock = new ReentrantLock();
private final Condition bufferNotFull = aLock.newCondition();
private final Condition bufferNotEmpty = aLock.newCondition();
public void put() throws InterruptedException {
aLock.lock();
try {
while (queue.size() == CAPACITY) {
System.out.println(Thread.currentThread().getName()
+ " : Buffer is full, waiting");
bufferNotEmpty.await();
}
int number = theRandom.nextInt();
boolean isAdded = queue.offer(number);
if (isAdded) {
System.out.printf("%s added %d into queue %n", Thread
.currentThread().getName(), number);
// signal consumer thread that, buffer has element now
System.out.println(Thread.currentThread().getName()
+ " : Signalling that buffer is no more empty now");
bufferNotFull.signalAll();
}
} finally {
aLock.unlock();
}
}
public void get() throws InterruptedException {
aLock.lock();
try {
while (queue.size() == 0) {
System.out.println(Thread.currentThread().getName()
+ " : Buffer is empty, waiting");
bufferNotFull.await();
}
Integer value = queue.poll();
if (value != null) {
System.out.printf("%s consumed %d from queue %n", Thread
.currentThread().getName(), value);
// signal producer thread that, buffer may be empty now
System.out.println(Thread.currentThread().getName()
+ " : Signalling that buffer may be empty now");
bufferNotEmpty.signalAll();
}
} finally {
aLock.unlock();
}
}
}
После того, что я изменить код и сделать его работу, как, First 10 Produce, затем 10 Потребляйте, цикл работает до тех пор, пока программа завершается. Вот мой модифицированный код:
class ProducerConsumerImpl {
// producer consumer problem data
private static final int CAPACITY = 10;
private final Queue<Integer> queue = new LinkedList<>();
private final Random theRandom = new Random();
// lock and condition variables
private final Lock aLock = new ReentrantLock();
private final Condition bufferNotFull = aLock.newCondition();
private final Condition bufferNotEmpty = aLock.newCondition();
public void put() throws InterruptedException {
aLock.lock();
try {
while(true){
while (queue.size() == CAPACITY) {
System.out.println(Thread.currentThread().getName()
+ " : Buffer is full, waiting");
bufferNotEmpty.await();
}
int number = theRandom.nextInt();
boolean isAdded = queue.offer(number);
if (isAdded) {
System.out.printf("%s added %d into queue %n", Thread
.currentThread().getName(), number);
}
bufferNotFull.signalAll();
}
} finally {
aLock.unlock();
}
}
public void get() throws InterruptedException {
aLock.lock();
try {
while(true){
while (queue.size() == 0) {
System.out.println(Thread.currentThread().getName()
+ " : Buffer is empty, waiting");
bufferNotFull.await();
}
Integer value = (Integer)queue.poll();
if (value != null) {
System.out.printf("%s consumed %d from queue %n", Thread
.currentThread().getName(), value);
}
bufferNotEmpty.signalAll();
}
} finally {
aLock.unlock();
}
}
}
После модификации Это прекрасно работает, производя 10 случайных чисел, а затем потребляя эти целые числа снова и снова, пока программы существуют/прекратить. Но поскольку я не мастер/эксперт по параллелизму.
Так что я хочу задать есть ли какие-либо проблемы в моем модифицированном коде?
У меня возникли проблемы с размещением на моем bufferNotFull.signalAll();
и bufferNotEmpty.signalAll();
, потому что каждый раз он мог уведомлять об ожидающем потоке.
Если есть проблема, то как я могу решить? или Если все в порядке, то, пожалуйста, также очистите мою путаницу bufferNotFull.signalAll(); and bufferNotEmpty.signalAll(); placement, because that could notify waiting thread each time.
.
Примечание: Это просто получить и установить код (производящими и потребляющими)
Выход измененного кода:.
PRODUCER added 1062016967 into queue
PRODUCER added 1204607478 into queue
PRODUCER added 1865840177 into queue
PRODUCER added -1279321362 into queue
PRODUCER added -190570442 into queue
PRODUCER added -1344361101 into queue
PRODUCER added 609239106 into queue
PRODUCER added -1480451794 into queue
PRODUCER added 1905208395 into queue
PRODUCER added -420578734 into queue
PRODUCER : Buffer is full, waiting
CONSUMER consumed 1062016967 from queue
CONSUMER consumed 1204607478 from queue
CONSUMER consumed 1865840177 from queue
CONSUMER consumed -1279321362 from queue
CONSUMER consumed -190570442 from queue
CONSUMER consumed -1344361101 from queue
CONSUMER consumed 609239106 from queue
CONSUMER consumed -1480451794 from queue
CONSUMER consumed 1905208395 from queue
CONSUMER consumed -420578734 from queue
CONSUMER : Buffer is empty, waiting
PRODUCER added 1917580670 into queue
so on.........
Edited Подумав в производительности я решил добавить если условие в обоих, put
и get
метод до signalall();
заявление. (Я думаю, что это может повысить производительность даже 0.000000Что-то) Но прерывать ожидание(); может быть deadlock();
Любая помощь?
Для Производитель:
if(queue.size() == CAPACITY){
bufferNotFull.signalAll();
}
Для потребителя:
if(queue.size() == 0){
bufferNotEmpty.signalAll();
}
Основываясь на выходе вашей программы, мне кажется, что она делает именно то, что она должна делать: производитель помещает вещи в очередь, потребитель берет их. Вы можете получить более «смешанные» результаты, если вы ставите циклы 'while (true)' вне циклов 'try' /' finally'. Затем вместо просмотра производителя/производителя/производителя/потребителя/потребителя/потребителя вы можете увидеть производителя/потребителя/производителя/потребителя/производителя/потребителя. –
Оригинальный код выглядит более естественным, чем ваша модификация, именно из-за комментария Брайана. Но исходный код использует путаное имя для переменных условия: 'bufferNotFull' для проверки того, что очередь ** не пуста ** и' bufferNotEmpty' для проверки того, что очередь ** не заполнена **. Обратите внимание: при попытке уменьшить время сигнализации (в конце вашего вопроса) вы используете естественный смысл имен переменных: 'bufferNotFull' с' queue.size() == CAPACITY' и 'bufferNotEmpty' с' queue.size() == 0'. – Tsyvarev
@ Цыварев спасибо за ваш комментарий. Хорошо понял. нет ли соглашения concurreny/deadlock/hack/thread-lock/thread-safe? – UnKnown