用阻塞队列和线程池简单实现生产者和消费者场景

本例子仅仅是博主学习阻塞队列和后的一些小实践,并不是真正的应用场景!

生产者消费者场景是我们应用中最常见的场景,我们可以通过ReentrantLock的Condition和对线程进行wait,notify同通信来实现生产者和消费者场景,前者可以实现多生产者和多消费者模式,后者仅可以实现一生产者,一消费者模式。

今天我们就利用阻塞队列来实现下生产者和消费者模式(里面还利用了线程池)。
看过我关于阻塞队列博文的朋友已经知道,阻塞队列其实就是由ReentrantLock实现的!

场景就不描述了,为简单的多生产者和多消费者!
上代码:

生产线程:

public class ProductThread extends Thread {
    private int taskNum;
    private ArrayBlockingQueue queue;
    public ProductThread(int taskNum,ArrayBlockingQueue queue) {
        this.taskNum = taskNum;
        this.queue = queue;
    }
    public void run() {
        try {
            //模拟生产
            Thread.currentThread().sleep(5000);
            System.out.println("开始生产");
            queue.add(taskNum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

消费线程:

public class ConsumerThread extends Thread {
    private ArrayBlockingQueue queue;
    public ConsumerThread(ArrayBlockingQueue queue) {
        this.queue = queue;
    }

    public void run() {
        System.out.println("准备消费");
            int taskNum;
            try {
                taskNum = (int) queue.take();
                System.out.println("消费了"+taskNum);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }   
    }
}

主线程(主方法):

public class ProductAndConsumer {

    public static void main(String[] args) {
        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(20);
        //为多生产者和多消费者分别开创的线程池
        ThreadPoolExecutor productPool = 
                new ThreadPoolExecutor(10,20,60,TimeUnit.MILLISECONDS,new ArrayBlockingQueue(5),new ThreadPoolExecutor.CallerRunsPolicy());
        ThreadPoolExecutor consumerPool = 
                new ThreadPoolExecutor(10,20,60,TimeUnit.MILLISECONDS,new ArrayBlockingQueue(5),new ThreadPoolExecutor.CallerRunsPolicy());

        System.out.println("start");
        for(int i = 0;i<100;i++) {

            productPool.execute(new ProductThread(i,queue));
            consumerPool.execute(new ConsumerThread(queue));
        }
        productPool.shutdown();
        consumerPool.shutdown();
    }
}

上面的代码,我为生产者和消费者分别开了线程池,因为在实际的应用中可能出现生产者和消费者不对等的情况,所以我们应该根据实际情况来设定线程池的参数,以适应不同场景!
在创建线程池的时候要加一个饱和处理的方式,我们上一节写线程池的饱和处理的时候有提及到,如果不加参数,会默认选择抛出异常,我上面选择的饱和策略是将饱和的任务交给调用线程(即主线程)处理,这个也应该根据实际情况来定,我们同样可以实现RejectedExecutionHandler接口,自己来定义这个饱和异常!

以上仅是博主学习自己写的例子,可能在一些情况下考虑的不周到,还请指教!
2018.4.18 21:31

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
阻塞队列线程池的搭配使用是为了提高程序的性能和效率,通过避免不必要的线程创建和销毁,减少资源消耗。阻塞队列线程池中起到任务缓存和通信的作用,它允许生产者(添加任务的线程)和消费者(执行任务的工作线程)之间进行有效的协作。当阻塞队列满时,添加任务的线程会被阻塞,直到队列中有空闲位置;当队列为空时,工作线程会被阻塞,直到队列中有新任务加入。 以下是阻塞队列线程池搭配使用的一些优点: 1. **提高响应速度**:线程池可以重用现有线程,减少线程创建和销毁的开销,从而提高性能和响应速度。 2. **避免资源过度消耗**:线程的创建和销毁是一个相对重量级的操作,线程池通过重用线程来执行多个任务,避免了资源的过度消耗。 3. **提高线程的可管理性**:线程池可以对线程进行统一的分配、调优和监控,提高了线程的可管理性。 4. **避免线程竞争死锁**:阻塞队列提供了等待/通知功能,用于线程间的通信,从而避免了线程竞争死锁的情况发生。 在使用阻塞队列线程池时,需要注意以下几点: 1. 选择合适的阻塞队列类型,如ArrayBlockingQueue、LinkedBlockingQueue等,根据不同的应用场景选择不同的队列特性。 2. 合理配置线程池的参数,如核心线程数、最大线程数、队列容量等,以确保线程池能够高效运行。 3. 考虑线程池的拒绝策略,当阻塞队列满时,需要有合适的策略来处理新添加的任务,如抛出异常、丢弃任务或创建新线程等。 相关问题: 1. 什么是阻塞队列? 2. 什么是线程池? 3. 阻塞队列线程池中的作用是什么?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值