繁体   English   中英

Java线程生产者和使用者

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

好的,您忘了做两件事:

  1. 消费和生产时更新变量n
  2. 用完后从列表中删除Mantou(这很难用列表完成,因此我建议改用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();
            }
        }
    }
}
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM