我正在编写一个小程序来使用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();
}}
答案 0 :(得分:0)
好的,你忘了做两件事:
另外,你的两个条件是不必要的......你可以用一个来做。这是工作代码:
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();
}
}
}
}
}
答案 1 :(得分:0)
我正在编写一个小程序来使用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(...);
}
唯一的诀窍就是知道你何时完成。通常人们通过添加一些常数来解决这个问题&#34;我们已经完成了#34;对象到队列。
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;
}
...