阻塞队列

并发编程几种主要的阻塞队列

阻塞队列 (BlockingQueue)是Java util.concurrent包下重要的数据结构BlockingQueue提供了线程安全的队列访问方式:当阻塞队列进行插入数据时,如果队列已满,线程将会阻塞等待直到队列非满;从阻塞队列取数据时,如果队列已空,线程将会阻塞等待直到队列非空。并发包下很多高级同步类的实现都是基于BlockingQueue实现的。

BlockingQueue 是个接口,你需要使用它的实现之一来使用BlockingQueue,Java.util.concurrent包下具有以下 BlockingQueue 接口的实现类:

ArrayBlockingQueue是一个有界的阻塞队列,其内部实现是将对象放到一个数组里。有界也就意味着,它不能够存储无限多数量的元素。它有一个同一时间能够存储元素数量的上限。你可以在对其初始化的时候设定这个上限,但之后就无法对这个上限进行修改了。

LinkedBlockingQueue:LinkedBlockingQueue 内部以一个链式结构(链接节点)对其元素进行存储。如果需要的话,这一链式结构可以选择一个上限。如果没有定义上限,将使用 Integer.MAX_VALUE 作为上限。

DelayQueue:DelayQueue 对元素进行持有直到一个特定的延迟到期。注入其中的元素必须实现 java.util.concurrent.Delayed 接口。

PriorityBlockingQueue:PriorityBlockingQueue 是一个无界的并发队列。它使用了和类 java.util.PriorityQueue 一样的排序规则。你无法向这个队列中插入 null 值。所有插入到 PriorityBlockingQueue 的元素必须实现 java.lang.Comparable 接口。因此该队列中元素的排序就取决于你自己的 Comparable 实现。

SynchronousQueue:SynchronousQueue 是一个特殊的队列,它的内部同时只能够容纳单个元素。如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。据此,把这个类称作一个队列显然是夸大其词了。它更多像是一个汇合点。

 

阻塞队列的实现原理

BlockingQueue提供了线程安全的队列访问方式:当阻塞队列进行插入数据时,如果队列已满,线程将会阻塞等待直到队列非满;从阻塞队列取数据时,如果队列已空,线程将会阻塞等待直到队列非空。

其实阻塞队列实现阻塞同步的方式很简单,使用的就是是lock锁的多条件(condition)阻塞控制。使用BlockingQueue封装了根据条件阻塞线程的过程,而我们就不用关心繁琐的await/signal操作了。

 

ArrayBlockingQueue

ArrayBlockingQueue 是一个用数组实现的有界阻塞队列,其内部按先进先出的原则对元素进行排序,其中put方法和take方法为添加和删除的阻塞方法,下面我们通过ArrayBlockingQueue队列实现一个生产者消费者的案例,通过该案例简单了解其使用方式

 // 生产者

public class Producer implements Runnable{

    //容器

    private final ArrayBlockingQueue<Bread> queue;

    public Producer(ArrayBlockingQueue<Bread> queue){

        this.queue = queue;

    }


    @Override

    public void run() {

        while(true){

            produce();

        }

    }
    

    public void produce(){

         // put()方法是如果容器满了的话就会把当前线程挂起

         //offer()方法是容器如果满的话就会返回false,也正是我在前一篇中实现的那种策略。

        try {

            Bread bread = new Bread();

            queue.put(bread);

            System.out.println("Producer:"+bread);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}


 

//消费者

public class Consumer implements Runnable{

    //容器

    private final ArrayBlockingQueue<Bread> queue;

    public Consumer(ArrayBlockingQueue<Bread> queue){

        this.queue = queue;

    }

    @Override

    public void run() {

        while(true){

            consume();

        }

    }


    public void consume(){

        /**

         * take()方法和put()方法是对应的,从中拿一个数据,如果拿不到线程挂起

         * poll()方法和offer()方法是对应的,从中拿一个数据,如果没有直接返回null

         */

        try {

            Bread bread = queue.take();

            System.out.println("consumer:"+bread);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}
//客户端

public class Client {

    public static void main(String[] args) {

        int capacity = 10;

        ArrayBlockingQueue<Bread> queue = new ArrayBlockingQueue<Bread>(capacity);

        new Thread(new Producer(queue)).start();

        new Thread(new Producer(queue)).start();

        new Thread(new Consumer(queue)).start();

        new Thread(new Consumer(queue)).start();

        new Thread(new Consumer(queue)).start();

    }

}

 

LinkedBlockingQueue

由于LinkedBlockingQueue实现是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选,LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.LinkedBlockingQueue;

 // 多线程模拟实现生产者/消费者模型

 public class BlockingQueueTest2 {

     //定义装苹果的篮子

    public class Basket {

        // 篮子,能够容纳3个苹果

        BlockingQueue<String> basket = new LinkedBlockingQueue<String>(3);

        // 生产苹果,放入篮子

        public void produce() throws InterruptedException {

            // put方法放入一个苹果,若basket满了,等到basket有位置

            basket.put("An apple");

        }



        // 消费苹果,从篮子中取走

        public String consume() throws InterruptedException {

            // take方法取出一个苹果,若basket为空,等到basket有苹果为止(获取并移除此队列的头部)

            return basket.take();

        }

    }



    // 定义苹果生产者

    class Producer implements Runnable {

        private String instance;

        private Basket basket;



        public Producer(String instance, Basket basket) {

            this.instance = instance;

            this.basket = basket;

        }



        public void run() {

            try {

                while (true) {

                    // 生产苹果

                    System.out.println("生产者准备生产苹果:" + instance);

                    basket.produce();

                    System.out.println("!生产者生产苹果完毕:" + instance);

                    // 休眠300ms

                    Thread.sleep(300);

                }

            } catch (InterruptedException ex) {

                System.out.println("Producer Interrupted");

            }

        }

    }



    // 定义苹果消费者

    class Consumer implements Runnable {

        private String instance;

        private Basket basket;



        public Consumer(String instance, Basket basket) {

            this.instance = instance;

            this.basket = basket;

        }



        public void run() {

            try {

                while (true) {

                    // 消费苹果

                    System.out.println("消费者准备消费苹果:" + instance);

                    System.out.println(basket.consume());

                    System.out.println("!消费者消费苹果完毕:" + instance);

                    // 休眠1000ms

                    Thread.sleep(1000);

                }

            } catch (InterruptedException ex) {

                System.out.println("Consumer Interrupted");

            }

        }

    }



    public static void main(String[] args) {

        BlockingQueueTest2 test = new BlockingQueueTest2();



        // 建立一个装苹果的篮子

        Basket basket = test.new Basket();



        ExecutorService service = Executors.newCachedThreadPool();

        Producer producer = test.new Producer("生产者001", basket);

        Producer producer2 = test.new Producer("生产者002", basket);

        Consumer consumer = test.new Consumer("消费者001", basket);

        service.submit(producer);

        service.submit(producer2);

        service.submit(consumer);

        // 程序运行5s后,所有任务停止

//        try {

//            Thread.sleep(1000 * 5);

//        } catch (InterruptedException e) {

//            e.printStackTrace();

//        }

//        service.shutdownNow();

    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值