【问题标题】:Java thread producer and consumerJava线程生产者和消费者
【发布时间】:2016-09-27 03:26:55
【问题描述】:

我正在编写一个小程序来使用ReentrantLock 而不是synchronized 的生产者和消费者问题。但是程序卡住了,因为一旦生产的物品被消费了,消费者线程将停止并且不再恢复消费。

代码sn-p:

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();
}}

【问题讨论】:

标签: java multithreading producer-consumer


【解决方案1】:

好吧,你忘了做两件事:

  1. 在消费和生产时更新变量 n
  2. 在消费后从列表中删除馒头(这对于列表来说很难做到,所以我建议改用 ArrayList)

另外,你的两个条件是不必要的......你可以只做一个。这是工作代码:

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();
            }
        }
    }
}
}

【讨论】:

    【解决方案2】:

    我正在编写一个小程序来使用 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;
     }
     ...
    

    【讨论】:

      猜你喜欢
      • 2012-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-13
      • 2013-11-17
      相关资源
      最近更新 更多