Java并发基础:PriorityBlockingQueue全面解析!

news2024/11/26 20:40:49

Java并发基础:PriorityBlockingQueue全面解析! - 程序员古德

内容概要

PriorityBlockingQueue类能高效处理优先级任务,确保高优先级任务优先执行,它内部基于优先级堆实现,保证了元素的有序性,同时,作为BlockingQueue接口的实现,它提供了线程安全的队列操作,适用于多线程环境下的任务调度与资源管理,简洁而强大的API使得开发者能轻松应对复杂的并发场景。

核心概念

PriorityBlockingQueue 实现了一个线程安全的优先级队列,在这个队列中,元素根据它们的自然排序(如果它们实现了 Comparable 接口)或者传递给队列构造器的 Comparator 进行排序。

比如有一个打印服务,在这个系统中,用户可以提交打印任务,每个任务都有一个优先级,高优先级的任务(比如紧急的文档)应该比低优先级的任务(如日常报告)更快地被处理。

在这个场景中,PriorityBlockingQueue 可以用来存储和管理待处理的打印任务,每当一个新的打印任务被提交时,它就被添加到队列中,由于 PriorityBlockingQueue 是一个优先级队列,所以高优先级的任务会自动排在队列的前面。

打印服务的工作线程可以从队列中取出任务来处理,由于队列是线程安全的,多个工作线程可以同时从队列中安全地取出任务,而且,由于队列会根据优先级对任务进行排序,所以工作线程总是先处理优先级最高的任务。

PriorityBlockingQueue 主要解决以下类似场景的问题:

  1. 并发访问:在多线程环境中,PriorityBlockingQueue 提供了安全的并发访问机制,多个线程可以同时向队列中添加或检索元素,而无需担心数据的不一致性或损坏。
  2. 优先级排序:队列中的元素根据其自然排序顺序或者传递给队列构造函数的比较器(Comparator)来排序,这使得在处理任务或消息时,可以确保首先处理优先级最高的项。
  3. 资源分配:在资源有限的情况下,PriorityBlockingQueue 可以帮助确定哪些任务或请求应该首先获得资源,通过为不同的任务设置不同的优先级,系统可以优先处理更重要的任务。
  4. 任务调度:在任务调度系统中,PriorityBlockingQueue 可用于管理待执行的任务,工作线程可以从队列中检索并执行优先级最高的任务,从而确保任务按照优先级顺序执行。
  5. 缓冲和流量控制:在高负载情况下,PriorityBlockingQueue 可以作为缓冲区来存储待处理的项目,并通过其阻塞特性来控制流量,当队列满时,尝试添加元素的线程将被阻塞,直到队列中有可用空间;同样地,当队列为空时,尝试检索元素的线程也将被阻塞,直到有元素可用。
  6. 延迟执行:虽然 PriorityBlockingQueue 本身不直接支持延迟执行,但可以通过结合使用优先级和自定义的比较器来实现类似的效果,例如,可以将任务的执行时间作为优先级的一部分,并确保在执行时间之前任务不会被检索出来。

代码案例

下面是一个简单例子,演示如何使用PriorityBlockingQueue类,这个例子中,创建了一个优先级阻塞队列,用于存储和检索Task对象,这些对象根据它们的优先级进行排序,client代码会向队列中添加任务,并从队列中检索并处理优先级最高的任务,如下:

import java.util.concurrent.PriorityBlockingQueue;  
  
// 任务类,实现了Comparable接口以便能够根据优先级进行排序  
class Task implements Comparable<Task> {  
    private int priority;  
    private String description;  
  
    public Task(int priority, String description) {  
        this.priority = priority;  
        this.description = description;  
    }  
  
    public int getPriority() {  
        return priority;  
    }  
  
    public String getDescription() {  
        return description;  
    }  
  
    // 根据优先级对任务进行排序,优先级高的任务排在前面  
    @Override  
    public int compareTo(Task other) {  
        // 注意:这里使用Integer.compare进行比较,以正确处理负数优先级  
        return Integer.compare(other.priority, this.priority); // 降序排列  
    }  
  
    @Override  
    public String toString() {  
        return "Task{" + "priority=" + priority + ", description='" + description + "'}";  
    }  
}  
  
// 客户端代码,演示如何使用PriorityBlockingQueue  
public class PriorityBlockingQueueExample {  
  
    public static void main(String[] args) throws InterruptedException {  
        // 创建一个优先级阻塞队列  
        PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();  
  
        // 向队列中添加任务  
        queue.put(new Task(3, "Low priority task"));  
        queue.put(new Task(5, "Medium priority task"));  
        queue.put(new Task(1, "Very low priority task"));  
        queue.put(new Task(7, "High priority task"));  
  
        // 从队列中检索并处理任务,直到队列为空  
        while (!queue.isEmpty()) {  
            // take方法会阻塞,直到队列中有元素可用  
            Task task = queue.take();  
            System.out.println("Processing task: " + task);  
        }  
    }  
}

在上面的代码中,创建了一个PriorityBlockingQueue实例,并向其中添加了四个具有不同优先级的任务,然后,使用一个循环从队列中检索并处理任务,直到队列为空,由于PriorityBlockingQueue是一个优先级队列,因此当从队列中检索任务时,优先级最高的任务总是首先被取出。

compareTo方法中,使用Integer.compare(other.priority, this.priority)来对任务进行降序排列,因此,优先级数值越高的任务将被视为优先级越高,并排在队列的前面,如果想要升序排列(即优先级数值越低的任务排在前面),可以简单地调换other.prioritythis.priority的位置。

上面代码输出如下类似内容:

Processing task: Task{priority=7, description='High priority task'}  
Processing task: Task{priority=5, description='Medium priority task'}  
Processing task: Task{priority=3, description='Low priority task'}  
Processing task: Task{priority=1, description='Very low priority task'}

核心API

PriorityBlockingQueue 实现了 BlockingQueue 接口并使用优先级堆对元素进行排序,以下是 PriorityBlockingQueue 类中一些常用方法的含义:

1、构造方法

  • PriorityBlockingQueue(): 创建一个具有默认初始容量的 PriorityBlockingQueue
  • PriorityBlockingQueue(int initialCapacity): 创建一个具有指定初始容量的 PriorityBlockingQueue
  • PriorityBlockingQueue(int initialCapacity, Comparator<? super E> comparator): 创建一个具有指定初始容量,并根据指定的比较器对元素进行排序的 PriorityBlockingQueue

2、插入方法

  • add(E e): 将指定的元素插入到此队列中,如果成功,则返回 true(由于队列没有容量限制,因此该方法总是返回 true,除非元素为 null)。
  • offer(E e): 将指定的元素插入到此队列中,并立即返回。该方法等效于 add(E e)
  • put(E e) throws InterruptedException: 将指定的元素插入到此队列中,等待必要的空间变得可用,如果当前线程被中断,则抛出 InterruptedException

3、移除方法

  • remove(Object o): 移除队列中首次出现的指定元素(如果存在)。
  • poll(): 检索并移除此队列的头,如果此队列为空,则返回 null
  • take() throws InterruptedException: 检索并移除此队列的头,等待元素变得可用,如果当前线程被中断,则抛出 InterruptedException

4、检查方法

  • peek(): 检索,但不移除此队列的头,如果此队列为空,则返回 null
  • element() throws NoSuchElementException: 检索,但不移除此队列的头,如果此队列为空,则抛出 NoSuchElementException

5、其他方法

  • size(): 返回队列中的元素数量。
  • isEmpty(): 如果队列为空,则返回 true
  • clear(): 移除此队列中的所有元素。
  • contains(Object o): 如果队列包含指定的元素,则返回 true
  • remainingCapacity(): 由于 PriorityBlockingQueue 没有容量限制,此方法始终返回 Integer.MAX_VALUE
  • drainTo(Collection<? super E> c): 移除此队列中所有可用的元素,并将它们添加到给定的集合中。
  • drainTo(Collection<? super E> c, int maxElements): 移除此队列中最多给定数量的可用元素,并将它们添加到给定的集合中。
  • toArray(): 返回包含队列中所有元素的数组。
  • iterator(): 返回在此队列元素上进行迭代的迭代器。注意,由于并发修改的可能性,迭代器的行为是弱一致的。
  • comparator(): 返回用于对此队列中的元素进行排序的比较器,如果此队列按其自然顺序排序,则返回 null

核心总结

Java并发基础:PriorityBlockingQueue全面解析! - 程序员古德

PriorityBlockingQueue类允许开发者存储元素并根据其自然排序或者提供的Comparator进行排序,其优点在于它能高效地处理需要优先级调度的任务,确保最高优先级的任务总是优先被处理,它的缺点是在高并发场景下,由于线程间的竞争,性能可能会受到影响,此外,虽然它提供了并发安全性,但在迭代过程中并不保证元素的顺序一致性。

关注我,每天学习互联网编程技术 - 程序员古德

END!

往期回顾

Java并发基础:DelayQueue全面解析!

Java并发基础:LinkedBlockingDeque全面解析!

Java并发基础:LinkedTransferQueue全面解析!

Java并发基础:LinkedBlockingQueue全面解析!

Java并发基础:Deque接口和Queue接口的区别?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1448933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

本地部署Stable Diffusion WebUI

官网 Stable Diffusion在线 Github上的Stable Diffusion WebUI 提醒一下&#xff1a;下面实例讲解是在Mac系统演示的&#xff1b; 一、 环境所需资源 PythonPycharmAnacondastable-diffusion-webui项目代码 注意事项 python版本一定要3.10&#xff0c;最好是3.10.6版本的。…

【使用IDEA总结】01——新增作者信息、方法参数返回值

[TOC](目录) 1.类新增作者信息 打开IDEA的Settings&#xff0c;Editor->Code Style->File and Code Templates->Includes->File Header&#xff0c;输入以下作者信息&#xff0c;作者名更换为自己的即可&#xff0c;操作如下图所示 /*** Author Linhaipeng* Date…

【Spring 校验】

校验 &#x1f347; 概述&#x1f349; 使用场景&#x1f349; 依赖引入 &#x1f34d; 校验示例&#x1f348;&#xff08;1&#xff09;在实体上标记校验注解&#x1f352;&#xff08;2&#xff09;在方法参数上声明校验注解&#x1f34f;&#xff08;3&#xff09;抛异常 &…

Unity(单元测试)在STM32上的移植与应用

概述 Unity Test是一个为C构建的单元测试框架。本文基于STM32F407为基础&#xff0c;完全使用STM32CubeIDE进行开发&#xff0c;移植和简单使用Unity。 单片机型号&#xff1a;STM32F407VET6 软件&#xff1a;STM32CubeIDE Version: 1.14.1 Unity Version&#xff1a;2.…

【报错解决】-bash: export: `-8‘: not a valid identifier 不是有效的标识符

现象 一登陆就提示-bash: export: -8’: not a valid identifier 不是有效的标识符 问题出现的原因 设置字符集时多写了空格 [rootdb1 ~]# cat >>/etc/profile<<EOF export LANGen_US.UTF -8(-8前不应有空格) EOF 解决方法 cd /etc vi profile 把export带有-8的…

第17讲我参与的投票列表实现

我参与的投票列表实现 sql: SELECT * FROM t_vote WHERE id IN (SELECT vote_id FROM t_vote_detail WHERE openido30ur5JpAsAUyGBkR0uW4IxvahR8)/*** 获取指定用户参与的投票* param token* return*/ RequestMapping("/listOfJoinUser") public R listOfJoinUser(R…

Hive的相关概念——分区表、分桶表

目录 一、Hive分区表 1.1 分区表的概念 1.2 分区表的创建 1.3 分区表数据加载及查询 1.3.1 静态分区 1.3.2 动态分区 1.4 分区表的本质及使用 1.5 分区表的注意事项 1.6 多重分区表 二、Hive分桶表 2.1 分桶表的概念 2.2 分桶表的创建 2.3 分桶表的数据加载 2.4 …

电脑上用什么软件恢复数据?2024年受欢迎的恢复软件推荐

在当今数字化的时代&#xff0c;电脑已经成为我们生活中不可或缺的工具。然而&#xff0c;由于各种原因&#xff0c;我们的电脑可能会出现数据丢失的情况。这时&#xff0c;一款好的数据恢复软件就显得尤为重要。本文将为大家介绍一款在2024年备受推崇的数据恢复软件&#xff0…

react渲染流程是怎样的

整体流程&#xff1a; react的核心可以用uifn(state)来表示&#xff0c;更详细可以用&#xff1a; const state reconcile(update); const UI commit(state);上面的fn可以分为如下一个部分&#xff1a; Scheduler&#xff08;调度器&#xff09;&#xff1a; 调度任务&…

Android adb使用超级大全

Android adb使用超级大全 ADB&#xff0c;即Android Debug Bridge&#xff0c;是一款强大的工具&#xff0c;对于Android开发/测试人员来说是不可或缺的&#xff0c;同时也是Android设备玩家的好玩具。本文将详细介绍ADB的使用方法。 ADB的基本用法如下&#xff1a; 命令语法…

Virt a Mate(VAM)游戏折腾记录

如有更新见原文&#xff1a;https://blog.iyatt.com/?p13283 1 前言 如果在网上看到有些视频名字带有 VAM 的&#xff0c;可能就是玩这个游戏录屏的。这个游戏可以建模、操作模型动作、构建场景等等。之前大致知道有这么个东西&#xff0c;只是电脑配置太差了&#xff0c;新…

java数据结构与算法刷题-----LeetCode459. 重复的子字符串

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 本题的高效解法&#xff0c;需要使用KMP算法中&#xff0c;NEXT数组的处理…

【机器学习案例3】从科学论文图片中提取标题、作者和摘要【含源码】

在这个项目中,我的目标是从科学论文图片中提取某些部分(标题、作者和摘要)。预期提取部分是科学论文中常见的部分,例如标题、摘要和作者。输入与最终结果。我的输入是将第一页纸转换成图像。最终结果是一个 txt 文件,其中包含标题、作者和摘要部分,如下图1和图2所示。我将…

【HTML】交友软件上照片的遮罩是如何做的

笑谈 我不知道大家有没有在夜深人静的时候感受到孤苦难耐&#xff0c;&#x1f436;。于是就去下了一些交友软件来排遣寂寞。可惜的是&#xff0c;有些交友软件真不够意思&#xff0c;连一些漂亮小姐姐的图片都要进行遮罩&#xff0c;完全不考虑兄弟们的感受,&#x1f620;。所…

steam游戏搬砖项目靠谱吗?有没有风险?

作为一款fps射击游戏&#xff0c;csgo在近几年可谓是火出圈&#xff0c;作为一款全球竞技游戏&#xff0c;深受玩家喜爱追捧&#xff0c;玩家追求的就是公平公正&#xff0c;各凭本事&#xff0c;像其他游戏可能还会有皮肤等装备属性加成&#xff0c;在csgo里面是不存在的。 纯…

AI短视频一键换脸小程序源码/带流量主

微信云开发AI一键视频换脸小程序源码是由极客二改后发布的&#xff0c;小程序增加了广告控制&#xff0c;插屏广告&#xff0c;激励广告和原生广告&#xff0c;由于采用了微信云开发没有后台&#xff0c;所以不需要域名和服务器也可以正常搭建使用&#xff0c;所有的配置都可以…

PR:序列的设置

新建序列 序列设置 将视频拖到时间轴上&#xff0c;如果视频的分辨率或帧率和序列设置不一致会有如下提示&#xff0c;保持现有设置即可

卡内基梅隆大学推出模块化爬行机器人,革新天然气管道维护技术!

天然气&#xff0c;作为典型清洁能源代表&#xff0c;在减缓环境污染和应对气候变暖中扮演着关键角色。在众多国家&#xff0c;它已跻身主要能源行列&#xff0c;在工业生产、供暖、电力生成等领埴发挥着核心作用。 天然气管道作为关键的能源传输纽带&#xff0c;为全球数以亿…

【JavaScript】面试手写题精讲之数组(上)

专题缘由 该专题主要是讲解我们在面试的时候碰到一些JS的手写题, 确实这种手写题还是比较恶心的。有些时候好不容易把题目写出来了&#xff0c;突然面试官冷不丁来一句有没有更优的解法&#xff0c;直接让我们僵在原地。为了解决兄弟们的这些困扰&#xff0c;这个专题于是就诞…

MySQL数据库⑩_视图+MySQL用户管理(增删查改)

目录 1. 视图的概念和规则限制 2. 视图的基本使用 2.1 创建视图 2.2 修改视图影响基表 2.3 修改基表影响视图 2.4 删除视图 3. MySQL用户管理 3.1 用户信息 3.2 创建用户 3.3 修改用户密码 3.4 删除用户 4. 用户权限 4.1 MySQL权限 4.2 给用户授权 4.3 回收权限…