Java线程生产者和消费者

时间:2016-09-27 03:26:55

标签: java multithreading producer-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();
}}

2 个答案:

答案 0 :(得分:0)

好的,你忘了做两件事:

  1. 在您使用和生成
  2. 时更新变量n
  3. 使用后从列表中删除馒头(这很难用于列表,因此我建议使用ArrayList)
  4. 另外,你的两个条件是不必要的......你可以用一个来做。这是工作代码:

    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;
 }
 ...