Java多线程专题-并发队列

在并发队列上JDK提供了两套实现,一个是以ConcurrentLinkedQueue为代表的高性能队列,一个是以BlockingQueue接口为代表的阻塞队列,无论哪种都继承自Queue。

 

ConcurrentLinkedQueue

是一个适用于高并发场景下的队列,通过无锁的方式,实现了高并发状态下的高性能,通常ConcurrentLinkedQueue性能好于BlockingQueue。它是一个基于链接节点的无界线程安全队列。该队列的元素遵循先进先出的原则。头是最先加入的,尾是最近加入的,该队列不允许null元素。

ConcurrentLinkedQueue重要方法:

  • add 和offer() 都是加入元素的方法(在ConcurrentLinkedQueue中这俩个方法没有任何区别)
  • poll() 和peek() 都是取头元素节点,区别在于前者会删除元素,后者不会。

BlockingQueue

BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种:

  1. 当队列满了的时候进行入队列操作
  2. 当队列空了的时候进行出队列操作

因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空队列进行出队列操作时,它将会被阻塞,除非有另一个线程进行了入队列操作。

在Java中,BlockingQueue的接口位于java.util.concurrent 包中(在Java5版本开始提供),由上面介绍的阻塞队列的特性可知,阻塞队列是线程安全的。

  • ArrayBlockingQueue: 通过数组实现的有边界的阻塞队列
  • LinkedBlockingQueue: 可配置边界大小,不配置则无边界,通过链表实现
  • PriorityBlockingQueue: 无边界有序的队列,元素必须实现Comparable接口
  • SynchronousQueue: 仅可容纳一个元素

ArrayBlockingQueue

ArrayBlockingQueue是一个有边界的阻塞队列,它的内部实现是一个数组。有边界的意思是它的容量是有限的,我们必须在其初始化的时候指定它的容量大小,容量大小一旦指定就不可改变。

ArrayBlockingQueue是以先进先出的方式存储数据,最新插入的对象是尾部,最新移出的对象是头部。

LinkedBlockingQueue

LinkedBlockingQueue阻塞队列大小的配置是可选的,如果我们初始化时指定一个大小,它就是有边界的,如果不指定,它就是无边界的。说是无边界,其实是采用了默认大小为Integer.MAX_VALUE的容量 。它的内部实现是一个链表。

和ArrayBlockingQueue一样,LinkedBlockingQueue 也是以先进先出的方式存储数据,最新插入的对象是尾部,最新移出的对象是头部。

​​​​​​​PriorityBlockingQueue

PriorityBlockingQueue是一个没有边界的队列,它的排序规则和 java.util.PriorityQueue一样。需要注意,PriorityBlockingQueue中允许插入null对象。

所有插入PriorityBlockingQueue的对象必须实现 java.lang.Comparable接口,队列优先级的排序规则就是按照我们对这个接口的实现来定义的。

另外,我们可以从PriorityBlockingQueue获得一个迭代器Iterator,但这个迭代器并不保证按照优先级顺序进行迭代。

​​​​​​​SynchronousQueue

SynchronousQueue队列内部仅允许容纳一个元素,但不会单独单独保存这个元素。当一个线程插入一个元素时会被阻塞,除非这个元素被另一个线程消费,如果一个线程获取元素时也会被阻塞,需要等到其他线程插入元素。

生产者与消费者案例

class Producer extends Thread {
    private BlockingQueue<String> queue;
    private AtomicInteger count = new AtomicInteger(0);
    private boolean flag = true;

    public Producer(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        System.out.println("生产线程启动...");
        while (flag) {
            String data = count.incrementAndGet() + "";
            System.out.println("已生产数据:" + data);
            try {
                boolean offer = queue.offer(data, 2, TimeUnit.SECONDS);
                if (offer) {
                    System.out.println("成功加入队列:" + data);
                } else {
                    System.out.println("加入队列失败:" + data);
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("生产线程停止...");
    }

    public void stopThread() {
        flag = false;
    }
}

class Customer extends Thread {
    private BlockingQueue<String> queue;
    private boolean flag = true;

    public Customer(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        System.out.println("消费线程启动...");
        try {
            while (flag) {
                String data = queue.poll(2, TimeUnit.SECONDS);
                if(data != null){
                    System.out.println("已消费数据:" + data + ",剩余:" + queue.size());
                }else{
                    System.out.println("消费数据失败:" + data);
                    flag = false;    
                }
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("消费线程停止...");
    }
}

public class ThreadDemo4 {
    public static void main(String[] args) throws Exception {
        BlockingQueue<String> queue = new LinkedBlockingQueue<String>(10);
        Producer producer1 = new Producer(queue);
        Producer producer2 = new Producer(queue);
        Customer customer = new Customer(queue);
        producer1.start();
        producer2.start();
        customer.start();
        Thread.sleep(20000);
        producer1.stopThread();
        producer2.stopThread();
    }
}

 

 

 

 

 

[JAVA工程师必会知识点之并发编程] 1、现在几乎100%的公司面试都必须面试并发编程,尤其是互联网公司,对于并发编程的要求更高,并发编程能力已经成为职场敲门砖。 2、现在已经是移动互联和大数据时代,对于应用程序的性能、处理能力、处理时效性要求更高了,传统的串行化编程无法充分利用现有的服务器性能。 3、并发编程是几乎所有框架的底层基础,掌握好并发编程更有利于我们学习各种框架。想要让自己的程序执行、接口响应、批处理效率更高,必须使用并发编程。 4、并发编程是中高级程序员的标配,是拿高薪的必备条件。 【优惠说明】 1、120余节视频课,原价299元,今日报名立减100,仅需199元 2、现在购课,就送价值800元的编程大礼包! 备注:请添加微信:itxy41,按提示获取讲师答疑服务。 【主讲讲师】 尹洪亮Kevin: 现任职某互联网公司首席架构师,负责系统架构、项目群管理、产品研发工作。 10余年软件行业经验,具有数百个线上项目实战经验。 擅长JAVA技术栈、高并发高可用伸缩式微服务架构、DevOps。 主导研发的蜂巢微服务架构已经成功支撑数百个微服务稳定运行 【推荐你学习这门课的理由:知识体系完整+丰富学习资料】 1、 本课程总计122课时,由五大体系组成,目的是让你一次性搞定并发编程。分别是并发编程基础、进阶、精通篇、Disruptor高并发框架、RateLimiter高并发访问限流吗,BAT员工也在学。 2、课程附带附带3个项目源码,几百个课程示例,5个高清PDF课件。 3、本课程0基础入门,从进程、线程、JVM开始讲起,每一个章节只专注于一个知识点,每个章节均有代码实例。 【课程分为基础篇、进阶篇、高级篇】 一、基础篇 基础篇从进程与线程、内存、CPU时间片轮训讲起,包含线程的3种创建方法、可视化观察线程、join、sleep、yield、interrupt,Synchronized、重入锁、对象锁、类锁、wait、notify、线程上下文切换、守护线程、阻塞式安全队列等内容。 二、进阶篇 进阶篇课程涵盖volatied关键字、Actomic类、可见性、原子性、ThreadLocal、Unsafe底层、同步类容器、并发类容器、5种并发队列、COW容器、InheritableThreadLocal源码解析等内容。 三、精通篇 精通篇课程涵盖JUC下的核心工具类,CountDownLath、CyclicBarrier、Phaser、Semaphore、Exchanger、ReentrantLock、ReentrantReadWriteLock、StampedLock、LockSupport、AQS底层、悲观锁、乐观锁、自旋锁、公平锁、非公平锁、排它锁、共享锁、重入锁、线程池、CachedThreadPool、FixedThreadPool、ScheduledThreadPool、SingleThreadExecutor、自定义线程池、ThreadFactory、线程池切面编程、线程池动态管理等内容,高并发设计模式,Future模式、Master Worker模式、CompletionService、ForkJoin等 课程中还包含 Disruptor高并发无锁框架讲解:Disruptor支持每秒600万订单处理的恐怖能力。深入到底层原理和开发模式,让你又懂又会用。 高并发访问限流讲解:涵盖木桶算法、令牌桶算法、Google RateLimiter限流开发、Apache JMeter压力测试实战。 【学完后我将达到什么水平?】 1、 吊打一切并发编程相关的笔试题、面试题。 2、 重构自己并发编程的体系知识,不再谈并发色变。 3、 精准掌握JAVA各种并发工具类、方法、关键字的原理和使用。 4、 轻松上手写出更高效、更优雅的并发程序,在工作中能够提出更多的解决方案。 【面向人群】 1、 总感觉并发编程很难、很复杂、不敢学习的人群。 2、 准备跳槽、找工作、拿高薪的程序员。 3、 希望提高自己的编程能力,开发出更高效、性能更强劲系统的人群。 4、 想要快速、系统化、精准掌握并发编程的人群。 【课程知识体系图】
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页