首页 > 编程语言 >Java数据结构-delayQueue-优先队列--信号量

Java数据结构-delayQueue-优先队列--信号量

时间:2024-06-04 10:33:09浏览次数:17  
标签:右移 Java -- lock 元素 信号量 队列 time Order

原编辑链接:
https://www.yuque.com/zhaozhaozhaozhao-khkij/lp7g2t/blwysxg3ygb00dw6?singleDoc# 《3delayqueue》

Queue问题

  • 单端队列和双端队列,分别对应的实现类是哪个?
    ○ Java中的单项队列queue是用链表实现的 , Queue本身是一个接口,继承了Collection集合 ;
    ○ 双端队列(Deque)继承了单向队列(Queue),也继承了其中所有的抽象方法,所以也包括基本队列的增删查方法。实现类:LinkedList、ArrayDeque、ConcurrentLinkedDeque、LinkedBlockingDeque ;
    在这里插入图片描述

  • 简述 延迟队列/优先队列 的实现方式 ?
    ○ 延迟队列实现:
    在这里插入图片描述在这里插入图片描述

○ 优先队列实现:
在这里插入图片描述在这里插入图片描述

○ 也就是这个图:在这里插入图片描述
其中delayed接口有两个方法需要重写,就是图中的获取延迟和比较

  • 二叉堆插入/弹出元素的过程 ?
    ○ 这个比较熟悉优先队列的二叉堆是一个小根堆:插入是自下向上的堆化,在队尾加入一个元素,然后不断向上找父节点,判断要是比父节点小就继续向上判断,否则就会停止找到自己的位置;删除是自上向下的堆化,pop出去根节点,然后把最后一个元素作为比较的key来自根节点向下找小数换到父节点,直到最后一个元素作为key找到自己的位置。

  • 延迟队列的使用场景?
    ○ 半小时未支付自动取消订单
    ○ 预定会议半小时前通知成员
    ○ 下单后消息提醒等等

  • 延迟队列为什么添加信号量?
    ○ 处理延迟任务时候,可能会有多个线程同时访问延迟队列就可能造成并发问题,为解决并发问题保证线程的安全性使用信号量来进行控制。这里的1代表只能允许一个线程同时访问队列。

Semaphore semaphore = new Semaphore(int permits 1, boolean fair);
// 构造方法
// public Semaphore(int permits) {
//     sync = new NonfairSync(permits);
// }

○ queue队列-基础数据结构-一种逻辑上的一端进一端出的结构,可以使用数组或者链表实现,逻辑上没有容量局限,可以无限入队出队。可以分为单端队列、双端队列;

1 java延迟队列说明–主要是这个好像用在消息机制中。好重要

应用场景电商平台会更多,对于数据量大实时性高的用延迟队列:
■ 半小时未支付自动取消订单
■ 预定会议半小时前通知成员
■ 下单后消息提醒等等

  1. JDK提供的API,位于java.util.concurrent包下;
  2. DelayQueue 是一个 BlockingQueue(无界阻塞)队列,它封装了一个使用完全二叉堆排序元素的 PriorityQueue(优先队列–二叉堆树结构)。
  3. 在添加元素时给元素一个 Delay(延迟时间)作为排序条件,队列中最小的元素会优先放到队首,元素到了delay时间才允许被取出;
  4. 队列中可以放基本数据类型或自定义实体类,在存放基本数据类型时,优先队列中元素默认升序排列,自定义实体类就需要根据类属性值比较计算了 。

2 delayQueue实现

  1. 延迟队列的实现,主要为在优先队列的基础上,添加可重入锁 ReentrantLock 对阻塞队列的实现。当数据存放时,按照二叉堆结构排序元素,出队时依照排序结构进行迁移。
  2. DelayQueue 的 put 方法是线程安全的,因为 put 方法内部使用了ReentrantLock进行线程同步。DelayQueue 还提供了两种出队的方法 poll() 和 take()。poll() 为非阻塞获取,没有到期的元素直接返回 null;take() 为阻塞方式获取,没有到期的元素线程将会等待。
    代码实现举例:
public class Order implements Delayed {
    //延迟时间
    @JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private long time;
    String name;

    public Order(String name, long time, TimeUnit unit) {
        this.name = name;
        this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0);
    } 
    //初始化给缓存时间了,就会设定时间time,后面执行会使用,比较或判断到不到时间

    @Override
    public long getDelay(TimeUnit unit) {
        return time - System.currentTimeMillis();
    }
    @Override
    public int compareTo(Delayed o) {
        Order Order = (Order) o;
        long diff = this.time - Order.time;
        if (diff <= 0) {
            return -1;
        } else {
            return 1;
        }
    }
}

//  test
public static void main(String[] args) throws InterruptedException {
    Order Order1 = new Order("Order1", 5, TimeUnit.SECONDS);
    Order Order2 = new Order("Order2", 10, TimeUnit.SECONDS);
    Order Order3 = new Order("Order3", 15, TimeUnit.SECONDS);
    DelayQueue<Order> delayQueue = new DelayQueue<>();
    delayQueue.put(Order1);
    delayQueue.put(Order2);
    delayQueue.put(Order3);

    System.out.println("订单延迟队列开始时间:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    while (delayQueue.size() != 0) {
        //取队列头部元素是否过期
        Order task = delayQueue.poll();
        if (task != null) {
            System.out.format("订单:{%s}被取消, 取消时间:{%s}\n", task.name, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
        Thread.sleep(1000);
    }
}
// 执行结果:Order1、Order2、Order3 分别在 5秒、10秒、15秒后被执行,

3操作实现

3.1 入队实现

入队一个元素会先直接插在队尾,然后执行优先队列的算法, 最终会调用到优先队列的 PriorityQueue # siftUpComparable 方法,就是小根堆的调整过程。
二叉堆:
在这里插入图片描述

3.2 出队实现

  • 出队直接弹出root节点,然后再次进行调整,但是这次不是自下向上调整,而是自上向下进行调整,寻找最小元素放到头顶;也是调用优先队列的 siftDownComparable
  • 调用参数是根节点下标0 最后一个元素作为比较的关键字key,队列数组,和最后一个元素的下标
private static <T> void siftDownComparable(int k, T x, Object[] es, int n) 

  • 实质是先把最后一个元素先放到根节点位置,然后不断下移,最小的元素不断上移,完成从上往下的堆化。

逻辑右移就是不考虑符号位,右移一位,左边补零即可。 算术右移需要考虑符号位,右移一位,若符号位为1,就在左边补1,;否则,就补0。
所以算术右移也可以进行有符号位的除法,右移,n位就等于除2的n次方。 例如,8位二进制数11001101分别右移一位。
逻辑右移就是[0]1100110 逻辑右移无脑补0 .
算术右移就是[1]1100110 算数右移补充的是原数据的符号位。

找左右孩子,找小的那个,最小的那个和父节点交换;再在最小那个孩子的位置作为父继续往下找,不断堆化,直到孩子都不比这个key小才停止。同时size–,最后一个已经加入到堆里面,将其置为空。
在这里插入图片描述

3.3 操作加锁

延迟队列关于元素的操作都会加锁处理。
offer:入队元素

public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
    q.offer(e);
    if (q.peek() == e) {
        available.signal();
    }
    return true;
} finally {
    lock.unlock();
}
}
poll:出队
public E poll() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        E first = q.peek();
        if (first == null || first.getDelay(NANOSECONDS) > 0) {
            return null;
        } else {
            return q.poll();
        }
    } finally {
        lock.unlock();
    }
}

出入队都保证线程安全。

标签:右移,Java,--,lock,元素,信号量,队列,time,Order
From: https://blog.csdn.net/wugemiao/article/details/139416720

相关文章

  • 《计算机网络微课堂》实验20 运输层端口
    下面我们来进行一个仿真实验,本仿真实验的目的在于验证TCP/IP运输层端口号的作用。我已经在仿真软件中构建好了这样一个网络拓扑,两台服务器和一台主机通过一台以太网交换机进行互联,属于同一个以太网,右边这台服务器用来充当WEB服务器,它的域名为www.porttest.com。IP地址为19......
  • 云服务器安装-DDD-部署总结笔记
    DDD部署笔记链接:https://www.yuque.com/zhaozhaozhaozhao-khkij/vxgn28/qct4gxgunq3zhd7r?singleDoc#《2DDD开发运维》这里格式要好点。资料来源:Linux|小傅哥bugstack虫洞栈内容包括开发基础环境、脚手架(项目工程搭建)、发布部署环境等等。2.1基础环境+脚手架●......
  • Node.js技术详解与前端工程化应用
    目录Node.js技术详解与前端工程化应用一、什么是Node.jsNode.js的作用什么是前端工程化Node.js为什么能执行JS二、Node.js的安装及使用步骤Node.js安装步骤使用Node.js2.1介绍fs模块2.2介绍path模块2.3介绍URL中的端口号2.4介绍http模块-创建Web服务三、Node.js模......
  • 怎么成为大模型开发工程师?
    利用工作之余的空闲时间,努力学习大模型知识吧。目前,这个行业对专业人才的需求量大,无论是大型企业还是中小型企业,都在迅速推进大模型应用的落地。但是,真正有实践经验并且能够将大模型应用落地的人才十分稀缺。OpenAI前段时间发布了重磅更新,使普通人和AI大模型交互的门槛......
  • 国产算力哪家强
    在国产算力领域,有多家企业表现出色,各自在不同的领域和细分赛道拥有较强的竞争力。以下是一些国产算力较强的企业及其特点:华为技术有限公司:作为国内知名的通信设备和智能手机制造商,华为的海思麒麟芯片在算力芯片领域有着出色的表现。该芯片采用了先进的制程工艺和架构设计,......
  • Java 开发面试题精选:Netty 一篇全搞定
    前言在面试Java开发工程师时,技术面试官不仅会考察候选人对Netty理论知识的掌握程度,还会考察其实际应用能力和问题解决技能。在本篇文章精选的关于Netty的面试题目中,从基础到实战再到一些问题的处理分析,都有所覆盖,能较为全面评估出候选人对Netty的理解和应用能力。如果你......
  • 代码随想录算法训练营Day60 | 84.柱状图中最大的矩形 | Python | 个人记录向
    注:今天是代码随想录训练营的最后一天啦!!!本文目录84.柱状图中最大的矩形做题看文章以往忽略的知识点小结个人体会84.柱状图中最大的矩形代码随想录:84.柱状图中最大的矩形Leetcode:84.柱状图中最大的矩形做题无思路。看文章与42.接雨水很像,42.接雨水是找每个......
  • JS面试题:hash和history的区别
    一、hash模式和history模式的介绍由于Vue项目为单页面应用,所以整个项目在开发和构建过程中,仅存在一个HTML物理文件。通过路由系统可以实现将项目的组件与可访问的URL路径进行绑定。由于Vue项目只有一个HTML物理文件,切换页面时既需要让访问的URL路径发生变化,又不能触发H......
  • 数据管理考核,如何避免陷入“形式主义”
    当企业颁布了越来越多的管理制度和规范标准,面临的一个核心问题,就是从上到下无论是领导,中高层还是员工有没有去执行。我们常常的做法就是进行巡检考核,通过排名奖惩的方式去推动大家落地执行。我们在执行考核排名的过程中,往往会出现人浮于事的情况。很多企业,到年底考核的时候,大......
  • 番茄时钟|FlowUs息流自带各种时间管理模版
    番茄时钟方法,又称为番茄工作法,是由弗朗西斯科·西里洛(FrancescoCirillo)在20世纪80年代末发明的一种时间管理工具。这个方法的核心是将工作时间分割成短小的、专注的时间段,通常为25分钟,称为一个“番茄时间”,之后休息5分钟,每完成四个番茄时间后,休息时间可以延长到15-30分钟。番......