生产者消费者模式模板总结

模板的核心:消费 / 生产方法

上锁
try{
    while(...){
        等待
    }
    进行消费 / 生产
    通知
}catch (InterruptedException e) {
    e.printStackTrace();
} finally {
	需要手动解锁,则释放锁
}

关键点:try{} 扩住整个逻辑,这是不会影响性能的。具体请百度了解。

这样后续的finally,就可以在ReetrankLock等实现中,手动地释放锁,不需要则为空即可。不用担心忘记释放锁。


首先提醒一下,网上很多实现的解锁不是在 finally块中的,都是错的,无法保证释放锁。

然后,还有很多的实现是: 一个大try 套小try

try{
    try{
        while(){等待}
    }catch(){}
    
	进行消费
	通知
}finally{
    解锁
}

这种实现上自然没有问题,只是代码就会显得很冗余( = =,主要是写了一个try 之后就会放松警惕),所以笔者认为一个try搞定是最好的。


本文正文已完,附上本人实现代码。需要的可以参考一下。

前置:

生产消费者的实现,大致可以分成两种

  1. 抽象出仓库类,仓库类内部有queue,阻塞该queue。

    生产者消费者,通过传入同一个仓库类,实现资源共享。在run方法中调用仓库类的方法即可

  2. 没有仓库类,生产消费者直接传入同一个队列。需要在 run 中 实现对应的生产、消费代码

本文采用第一种,抽象出仓库类。

而实现仓库类,常见的就是synchronized、ReentrantLock、直接用阻塞队列 三种。

本文只附上前两种实现,因为和模板比较贴合。

ps : 可以让两种实现同一个接口,测试起来会很方法,直接更改上转型对象即可

// 抽象个接口,方便测试不同的,实际没必要
public interface Storage {
    void consume();
    void produce();
}
测试的时候,直接更改实现类就可以了,很方便
//        Storage storage = new StorageSync(10);
        Storage storage = new StorageLock(10);

synchronized实现:

import java.util.LinkedList;

// 抽象个接口,方便测试不同的,实际没必要
public class StorageSync implements Storage {

    //资源池中允许存放的资源数目
    private int capacity;

    private LinkedList<Integer> queue;
    // 资源id,测试用
    int i = 1;

    public StorageSync(int capacity) {
        this.capacity = capacity;
        this.queue = new LinkedList<>();
    }

    public void consume() {
        // 阻塞queue
        synchronized (queue) {
            // 其实只括await的部分就可以,不过为了整合Lock的实现。
            // 但不影响性能
            try {
                // 自旋等待, 一定要用while,防止虚假唤醒 notifyAll
                while (queue.size() == 0) {
                    System.out.println("【消费者" + Thread.currentThread().getName()
                            + "】仓库为空");
                    queue.wait();
                }

                int i = queue.removeLast();
                System.out.println("【消费者" + Thread.currentThread().getName()
                        + "】消费一个产品" + i + ",现库存" + queue.size());
                queue.notifyAll();//通知生产者生产资源
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }

    public void produce() {
        synchronized (queue) {
            try {
                while (queue.size() == capacity) {
                    System.out.println("【生产者" + Thread.currentThread().getName()
                            + "】仓库已满");
                    //生产者进入等待状态,并释放锁
                    queue.wait();
                }

                queue.addFirst(i);
                System.out.println("【生产者" + Thread.currentThread().getName()
                        + "】生产一个产品:" + i++ + ",现库存" + queue.size());
                queue.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public int getNum() {
        return queue.size();
    }
}

Lock实现:

// 抽象个接口,方便测试不同的,实际没必要
public class StorageLock implements Storage {
    private int capacity;

    private LinkedList<Integer> queue;
    // 资源id,测试用
    int i = 1;

    // final ,防止改变
    private final ReentrantLock lock = new ReentrantLock();

    // 消费者等待的条件 ,资源为0时等待
    private final Condition consumerEmpty = lock.newCondition();

    // 同,资源满了
    private final Condition producerFull = lock.newCondition();


    public StorageLock(int capacity) {
        this.capacity = capacity;
        this.queue = new LinkedList<>();
    }

    public void consume() {
        lock.lock();
        try {
            while (queue.size() == 0) {
                System.out.println("【消费者" + Thread.currentThread().getName()
                        + "】仓库为空");
                consumerEmpty.await();
            }
            int i = queue.removeLast();
            System.out.println("【消费者" + Thread.currentThread().getName()
                    + "】消费一个产品" + i + ",现库存" + queue.size());
            producerFull.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }

    public void produce() {
        lock.lock();
        try {
            while (queue.size() == capacity) {
                System.out.println("【生产者" + Thread.currentThread().getName()
                        + "】仓库已满");
                producerFull.await();
            }
            queue.addFirst(i);
            System.out.println("【生产者" + Thread.currentThread().getName()
                    + "】生产一个产品:" + i++ + ",现库存" + queue.size());

            consumerEmpty.signalAll();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public int getNum() {
        return queue.size();
    }
}

生产、消费者、及测试类

package back.interview.ConsumerProducer;

import back.interview.ConsumerProducer.Storage.Storage;
import back.interview.ConsumerProducer.Storage.StorageLock;

class Producer implements Runnable {
    private Storage storage;

    // 传入storage
    public Producer(Storage storage) {
        this.storage = storage;
    }

    public void run() {
//        storage.produce();
        while (true) {
            try {
                Thread.sleep(1000);
                storage.produce();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


class Consumer implements Runnable {
    private Storage storage;

    public Consumer(Storage storage) {
        this.storage = storage;
    }

    public void run() {
//        storage.consume();

        while (true) {
            try {
                Thread.sleep(3000);
                storage.consume();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class test {
    public static void main(String[] args) {
        
//        Storage storage = new StorageSync(10);
        Storage storage = new StorageLock(10);

        // 关键,传入同一个Storage ,完成资源共享
        
        Thread p1 = new Thread(new Producer(storage));
        Thread p2 = new Thread(new Producer(storage));
        Thread p3 = new Thread(new Producer(storage));

        Thread c1 = new Thread(new Consumer(storage));
        Thread c2 = new Thread(new Consumer(storage));
        Thread c3 = new Thread(new Consumer(storage));

        p1.start();
        p2.start();
        p3.start();
        c1.start();
        c2.start();
        c3.start();
    }

}

本文完,有误欢迎指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值