Java高并发BlockingQueue重要的实现类详解

Java高并发BlockingQueue重要的实现类详解

概述

在Java中,BlockingQueue是一种很重要的线程安全容器,它提供了线程安全的数据存储和获取操作,用于在多线程并发场景中实现生产者-消费者模式的应用。本文将详细介绍BlockingQueue的相关实现类,包括ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue和PriorityBlockingQueue。

ArrayBlockingQueue

ArrayBlockingQueue是通过数组实现的阻塞队列,其容量固定,不能动态增加或减少。ArrayBlockingQueue的元素插入和删除都会阻塞,直到对应的操作可以被执行,所以是一个“阻塞”的队列。在多线程并发场景中,生产者生产的速度很快,如果队列满了,则会阻塞当前线程,直到队列中有元素被消费。另外,ArrayBlockingQueue是公平的队列,即多个线程访问队列时,它们的顺序与请求的顺序一样。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ArrayBlockingQueueDemo {

  public static void main(String[] args) {
    BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
    new Thread(() -> {
      try {
        queue.put("A");
        queue.put("B");
        queue.put("C");
        System.out.println(Thread.currentThread().getName() + " 生产 ABC 完成");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Producer").start();

    new Thread(() -> {
      try {
        Thread.sleep(1000); // 线程 B 在 1000ms 后开始消费
        queue.take();
        queue.take();
        System.out.println(Thread.currentThread().getName() + " 消费 AB 完成");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Consumer1").start();

    new Thread(() -> {
      try {
        Thread.sleep(2000); // 线程 C 在 2000ms 后开始消费
        queue.take();
        System.out.println(Thread.currentThread().getName() + " 消费 C 完成");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Consumer2").start();
  }

}

上面的示例代码中,创建了一个大小为 3 的ArrayBlockingQueue,启动一个生产者线程生产 ABC 三个元素,启动两个消费者线程分别消费两个元素和一个元素。由于队列大小为 3,所以生产者生产完 ABC 后就会阻塞等待,直到有消费者线程消费元素。消费者线程也会阻塞等待队列中有元素才开始消费。

LinkedBlockingQueue

LinkedBlockingQueue是通过链表实现的阻塞队列,其容量可以动态增加或减少(没有指定容量则使用默认容量Integer.MAX_VALUE)。LinkedBlockingQueue同样是一个“阻塞”的队列,在多线程并发场景中,当队列满了时,生产者线程会被阻塞,直到队列中有元素被消费;当队列为空时,消费者线程会被阻塞,直到队列中有元素被生产。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class LinkedBlockingQueueDemo {

  public static void main(String[] args) {
    BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);
    new Thread(() -> {
      try {
        queue.put("A");
        queue.put("B");
        queue.put("C"); // 生产 C 时会被阻塞,因为队列已满
        System.out.println(Thread.currentThread().getName() + " 生产 ABC 完成");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Producer").start();

    new Thread(() -> {
      try {
        Thread.sleep(1000); // 线程 B 在 1000ms 后开始消费
        queue.take();
        queue.take();
        System.out.println(Thread.currentThread().getName() + " 消费 AB 完成");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Consumer1").start();

    new Thread(() -> {
      try {
        Thread.sleep(2000); // 线程 C 在 2000ms 后开始消费
        queue.take();
        System.out.println(Thread.currentThread().getName() + " 消费 C 完成");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Consumer2").start();
  }

}

上面的示例代码中,创建了一个大小为 2 的LinkedBlockingQueue,启动一个生产者线程生产 ABC 三个元素,启动两个消费者线程分别消费两个元素和一个元素。由于队列大小为 2,所以生产者生产完 AB 后就会阻塞等待,直到有消费者线程消费元素。消费者线程也会阻塞等待队列中有元素才开始消费。

SynchronousQueue

SynchronousQueue是一种直接传递队列,不会保存任何元素,每一个插入操作必须等待另一个线程的移除操作,反之亦然。在多线程并发场景中,SynchronousQueue是一个异步交换数据的容器,生产者线程会等待消费者线程处理数据,消费者线程也会等待生产者线程提供数据。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;

public class SynchronousQueueDemo {

  public static void main(String[] args) {
    BlockingQueue<String> queue = new SynchronousQueue<>();
    new Thread(() -> {
      try {
        queue.put("A"); // 生产 A 后会等待消费者消费掉 A
        System.out.println(Thread.currentThread().getName() + " 生产 A 完成");
        queue.put("B"); // 生产 B 后会等待消费者消费掉 B
        System.out.println(Thread.currentThread().getName() + " 生产 B 完成");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Producer").start();

    new Thread(() -> {
      try {
        Thread.sleep(1000); // 线程 B 在 1000ms 后开始消费
        queue.take(); // 消费 A
        System.out.println(Thread.currentThread().getName() + " 消费 A 完成");
        Thread.sleep(2000); // 线程 C 在 2000ms 后开始消费
        queue.take(); // 消费 B
        System.out.println(Thread.currentThread().getName() + " 消费 B 完成");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }, "Consumer").start();
  }

}

上面的示例代码中,创建了一个SynchronousQueue,启动一个生产者线程生产 A 和 B 两个元素,启动一个消费者线程分别消费 A 和 B。由于SynchronousQueue是一种同步传递队列,生产者和消费者线程之间必须一对一收发消息,每个插入操作必须等待另一个线程的移除操作,反之亦然,所以在生产者生产 A 和 B 后会等待消费者消费掉,消费者线程也会等待生产者线程提供数据。

PriorityBlockingQueue

PriorityBlockingQueue是一个支持优先级的无界阻塞队列,其排序原则是自然顺序(数字从小到大、字符串按字典序)或比较器顺序,与普通队列不同的是,PriorityBlockingQueue内部是无锁的,它使用了可重入锁 ReentrantLock、条件变量 Condition 和 CAS等技术来保证线程安全。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;

public class PriorityBlockingQueueDemo {

  static class Person implements Comparable<Person> {

    private String name;
    private Integer age;

    public Person(String name, Integer age) {
      this.name = name;
      this.age = age;
    }

    @Override
    public int compareTo(Person o) {
      return age.compareTo(o.age);
    }

    @Override
    public String toString() {
      return "Person{" +
          "name='" + name + '\'' +
          ", age=" + age +
          '}';
    }

  }

  public static void main(String[] args) {
    BlockingQueue<Person> queue = new PriorityBlockingQueue<>();
    queue.add(new Person("Tom", 18));
    queue.add(new Person("Jim", 22));
    queue.add(new Person("Jack", 20));

    System.out.println("队首元素:" + queue.peek());
    System.out.println("队列长度:" + queue.size());

    System.out.println(queue.poll());
    System.out.println(queue.poll());
    System.out.println(queue.poll());
    //System.out.println(queue.poll()); // 队列为空时,继续出列会返回null
  }

}

上面的示例代码中,创建了一个大小为 3 的PriorityBlockingQueue,元素类型为Person,它根据每个Person实例的年龄age属性进行优先级排序。元素插入时会根据年龄自动排序,元素出队时先出优先级最高的元素。另外,PriorityBlockingQueue是一个无界队列,在没有插入元素时,它的队列长度为 0。

总结

BlockingQueue是一个很实用、很重要的线程安全容器,它提供了线程安全的数据存储和获取操作,用于在多线程并发场景中实现生产者-消费者模式的应用。本文介绍了Java高并发情况下常用的BlockingQueue实现类,包括ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue和PriorityBlockingQueue。在实际开发中,要根据场景选择合适的BlockingQueue实现类,以提高程序的可靠性和性能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java高并发BlockingQueue重要的实现类详解 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • Java线程池并发执行多个任务方式

    当需求场景为处理大量并发任务时,我们通常使用线程池来优化性能。Java线程池可以控制并发线程数量,避免资源超额占用以及线程切换开销过大的问题。常见的线程池类有ThreadPoolExecutor和Executors等。在使用线程池时,我们可以通过不同的线程池参数及处理方式控制任务执行效率。 一、Java线程池的创建 //创建线程池 ExecutorServi…

    多线程 2023年5月16日
    00
  • Python threading多线程编程实例

    Python threading是一个多线程编程模块,使用它可以让程序在多个线程中同时执行代码。在某些情况下,多线程可以提高程序的执行效率和性能。以下是Python threading多线程编程的完整攻略。 理解多线程编程 多线程编程是指在程序中同时运行多个线程,每个线程可以独立执行不同的代码。这个过程中,多线程共享代码的散列表、全局变量和堆栈等内存空间,但…

    多线程 2023年5月17日
    00
  • MySQL中SELECT+UPDATE处理并发更新问题解决方案分享

    MySQL中SELECT+UPDATE处理并发更新问题解决方案分享 在MySQL中,常常存在多个客户端同时对同一行数据进行更新的情况,这就导致了并发更新问题,会产生脏读、幻读等问题。接下来,我们将为大家分享如何通过SELECT+UPDATE来解决并发更新问题。 解决方案 MySQL提供了多种方式来解决并发更新问题,比如使用事务或者锁机制。而在本文中,我们将介…

    多线程 2023年5月17日
    00
  • Java并发线程池实例分析讲解

    Java并发线程池实例分析讲解 什么是线程池 线程池是一种用于管理多线程的机制,它可以维护一个线程队列,并在这些线程中动态地执行任务。线程池实现了资源的重复利用,在多线程应用中表现出色,可以提高系统的性能。 如何使用线程池 Java提供了一个Executor框架,用于从应用程序中的请求中分离出任务的执行和管理。Java.util.concurrent.Exe…

    多线程 2023年5月16日
    00
  • Java多线程 自定义线程池详情

    Java多线程 自定义线程池详情 什么是线程池? 线程池是一种线程复用的机制,用于管理与分配线程。在程序中,线程池预先为一组可重用的线程分配了一定数量的线程。这些线程对于一定数量的任务是可用的。一旦指定了任务,就将任务放入队列中排队等待线程。一旦有可用的线程,它就会从队列中取出一个任务并处理它。 JDK内置的线程池 在JDK中,可以使用Executors类创…

    多线程 2023年5月17日
    00
  • Android多线程学习实例详解

    Android多线程学习实例详解 为什么需要多线程? 在Android开发中,我们经常需要进行异步的操作,比如网络请求、文件读写等等。如果这些操作都放在主线程上执行,就会导致UI线程阻塞,使得用户界面无法响应用户的操作,影响用户体验。而异步操作的一种常见的处理方法就是采用多线程。 多线程基本概念 线程和进程 线程(Thread)是操作系统中独立执行的最小单元…

    多线程 2023年5月17日
    00
  • Node.js 与并发模型的详细介绍

    Node.js 与并发模型的详细介绍 什么是 Node.js Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它的特点是以事件驱动、非阻塞 I/O 模型而著名。 Node.js 因为使用 V8 引擎,可以获得与 Google Chrome 相同的快速性能。同时,它可以直接在本地运行 JavaScript,也可以作为服务…

    多线程 2023年5月16日
    00
  • C#制作多线程处理强化版网络爬虫

    C#制作多线程处理强化版网络爬虫攻略 定义网络爬虫 网络爬虫是一种程序,能够自动抓取互联网上的信息,其核心思想就是在Web上自动抓取数据信息,并自动分析处理数据。 如何制作多线程处理强化版网络爬虫 要制作多线程处理强化版网络爬虫,首先需要明确以下几点: 采用哪种语言 如何建立爬虫任务列表 如何设计数据库存储 如何利用多线程处理任务列表 本文将介绍如何使用C#…

    多线程 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部