簡體   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