多线程之 生产者消费者问题

本文探讨了生产者消费者问题,设计了一个容器,具有put和get方法及最大容量,允许2个生产者和10个消费者在达到容器满或空时阻塞。内容涉及线程协作,讲解了wait和notify方法的使用,强调了wait不会立即释放锁,而notifyAll可能造成不必要的唤醒。最后提到了使用ReentrantLock来改进这一问题。
摘要由CSDN通过智能技术生成

生产者消费者问题

设计一个容器,有put和get方法和最大容量,能够让2个生产者,10个消费者同时阻塞调用。

涉及到线程间的协作,如wait和notify方法。
wait和notify是object类的两个方法,锁.wait() 相当于将当前持有锁的这个线程wait,锁.notify() 相当于通知阻塞的线程可以醒来竞争获得锁了。
需要注意的是 notify并不释放锁,只有代码运行完或者抛出异常才释放锁
代码如下:

public class TestMyContaine<T> {
    private List<T> lists = new LinkedList<>(); // linkedList删除新增元素效率更高
    private int MAX = 10; // 最大容量
    private int count;

    // 加上同步锁
    public synchronized void put(T t) {
        // 想一下这里为什么要用while,而不能用if
        while (this.count == MAX){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        lists.add(t);
        ++ count;
        // 唤醒所有wait的线程,因为notify只唤醒随机一个,不建议使用
        this.notifyAll();
    }

    public synchronized T get(){
        T t = null;
        while (this.count == 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
       t = lists.remove(0);
        -- count;
        this.notifyAll();
        return t;
    }
}

测试
在这里插入图片描述
但这个还有一点瑕疵:notifyAll()是唤醒所有阻塞的线程,但如果是消费者进行notify,那只需要唤醒所有阻塞的生产者就行了;同理生产者只需唤醒所有阻塞的消费者。
可使用ReentranLock解决

public class TestMyContaine2<T> {
    private List<T> lists = new LinkedList<>(); // linkedList删除新增元素效率更高
    private int MAX = 10; // 最大容量
    private int count;

    private Lock lock = new ReentrantLock();
    // consumer,producer相当于2个单独的队列,调用其await时,将线程阻塞并放入对应这个队列
    // 调用singleAll时,唤醒所有队列里的线程,竞争拿锁
    private Condition consumer = lock.newCondition();
    private Condition producer = lock.newCondition();

    public  void put(T t) {
        lock.lock(); // 加锁
        // 想一下这里为什么要用while,而不能用if
        while (this.count == MAX){
            try {
                producer.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        lists.add(t);
        ++ count;
        consumer.signalAll();
        lock.unlock();
    }

    public  T get(){
        T t = null;
        try{
            lock.lock();
            while (this.count == 0){
                try {
                    consumer.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            t = lists.remove(0);
            -- count;
            producer.signalAll();

        }catch (Exception e){
        }
        finally {
            lock.unlock();
        }
        return t;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值