[英]Java thread producer and consumer
我正在編寫一個小程序來使用ReentrantLock
而不是synchronized
生產者和使用者問題。 但是程序卡住了,因為一旦消費了生產的商品,消費線程將停止並且永遠不會恢復消費。
程式碼片段:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Mantou2 {
int id;
public Mantou2(int id) {
this.id = id;
}}
class Basket2 {
final int max = 20;
Mantou2[] ms;
int n;
Lock lock;
Condition full;
Condition empty;
public Basket2() {
ms = new Mantou2[max];
n = 0;
lock = new ReentrantLock();
full = lock.newCondition();
empty = lock.newCondition();
}
public void consume() {
lock.lock();
try {
while (n == 0) {
System.out.println("No Mantou left!");
empty.await();
}
empty.signal();
System.out.println(ms[--n].id + " consumed and " + n + " left");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void produce() {
lock.lock();
try {
while (n == max) {
System.out.println("Inventory is full!");
full.await();
}
full.signal();
ms[n] = new Mantou2(n++);
System.out.println(ms[n - 1].id + " produced and " + n + " left");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}}
class Consumer2 implements Runnable {
Basket2 basket;
public Consumer2(Basket2 basket) {
this.basket = basket;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
basket.consume();
try {
Thread.sleep((long) (Math.random() * 300));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}}
class Producer2 implements Runnable {
Basket2 basket;
public Producer2(Basket2 basket) {
this.basket = basket;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
basket.produce();
try {
Thread.sleep((long) (Math.random() * 300));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}}
public class ProducerCustomer2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Basket2 basket = new Basket2();
Producer2 producer = new Producer2(basket);
Consumer2 consumer = new Consumer2(basket);
Thread p = new Thread(producer);
Thread c = new Thread(consumer);
p.start();
c.start();
}}
好的,您忘了做兩件事:
另外,您不需要兩個條件……您可以只用一個條件。 這是工作代碼:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.ArrayList;
public class ProducerCustomer2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
ProducerCustomer2 pc = new ProducerCustomer2();
pc.start();
}
public void start() {
Basket2 basket = new Basket2();
Producer2 producer = new Producer2(basket);
Consumer2 consumer = new Consumer2(basket);
Thread p = new Thread(producer);
Thread c = new Thread(consumer);
p.start();
c.start();
}
private class Mantou2 {
int id;
public Mantou2(int id) {
this.id = id;
}
}
private class Basket2 {
final int max = 20;
ArrayList<Mantou2> ms;
int n;
Lock lock;
Condition full;
Condition empty;
public Basket2() {
ms = new ArrayList<Mantou2>();
n = 0;
lock = new ReentrantLock();
full = lock.newCondition();
empty = lock.newCondition();
}
public void consume() {
lock.lock();
try {
while (n == 0) {
System.out.println("No Mantou left!");
full.await();
}
System.out.println(ms.get(n-1).id + " consumed and " + n + " left");
ms.remove(n-1);
n--;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
full.signal();
lock.unlock();
}
}
public void produce() {
lock.lock();
try {
while (n == max) {
System.out.println("Inventory is full!");
full.await();
}
n++;
ms.add(new Mantou2(n));
System.out.println(ms.get(n-1).id + " produced and " + n + " left");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
full.signal();
lock.unlock();
}
}
}
private class Consumer2 implements Runnable {
Basket2 basket;
public Consumer2(Basket2 basket) {
this.basket = basket;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
basket.consume();
try {
Thread.sleep((long) (Math.random() * 300));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private class Producer2 implements Runnable {
Basket2 basket;
public Producer2(Basket2 basket) {
this.basket = basket;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 50; i++) {
basket.produce();
try {
Thread.sleep((long) (Math.random() * 300));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
我正在編寫一個小程序來使用ReentrantLock,而不是同步生產者和使用者問題。
也許這是一個學術問題,但如果不是,您絕對應該使用BlockingQueue
作為解決方案。 例如, LinkedBlockingQueue
負責所有同步,計數,復雜性等。代碼如下所示:
BlockingQueue<Mantou2> queue = new LinkedBlockingQueue<>(20);
// producer
for (int i = 0; i < 50; i++) {
queue.add(new Mantou2(i));
Thread.sleep(...);
}
// consumer
for (int i = 0; i < 50; i++) {
Mantou2 mantou2 = queue.take();
System.out.println(mantou2.id + " consumed and " + queue.size() + " left");
Thread.sleep(...);
}
唯一的技巧是知道何時完成。 通常,人們通過在隊列中添加一些恆定的“我們已完成”對象來解決此問題。
private final Mantou2 WE_ARE_DONE = new Mantou2();
...
// producer says that we are done
queue.add(WE_ARE_DONE);
...
// consumer
Mantou2 mantou2 = queue.take();
if (mantou2 == WE_ARE_DONE) {
break;
}
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.