阻塞队列和定时器的使用
阻塞队列
谈到队列,大家就能想到队列的先进先出原则,但有些特殊的队列,虽然也是先进先出的,但是带有阻塞功能,我们把这种队列叫做阻塞队列.
★如果队列为空,执行出队操作就会阻塞,阻塞到另外一个线程往队列里添加元素(队列不为空)为止.
★如果队列满了,执行入队操作时,也会阻塞,阻塞到另外一个线程从队列里取出元素(队列不满).
想要了解阻塞队列,先了解生产者-消费者模型,这个模型给我们程序带来了非常重要的好处
1.生产者-消费者模型
在一个餐馆中,有多名厨师(生产者)负责烹饪菜品,并将其放在共享的出菜区(缓冲区)上。而服务员(消费者)则从出菜区上取出菜品并端给顾客。这里的厨师可以看作是生产者,出菜区是缓冲区,服务员是消费者。
1. 实现了生产者和消费者之间的 "解耦"
我们写代码要追求低耦合,所谓解耦操作,就是降低耦合的过程.
比如过年一家人一起包饺子. 一般都是有明确分工 , 比如一个人负责擀饺子皮 , 其他人负责包 . 擀饺 子皮的人就是 "生产者", 包饺子的人就是 " 消费者 ".擀饺子皮的人不关心包饺子的人是谁( 能包就行 , 无论是手工包 , 借助工具 , 还是机器包 ), 包饺子的人 也不关心擀饺子皮的人是谁( 有饺子皮就行 , 无论是用擀面杖擀的 , 还是拿罐头瓶擀 , 还是直接从超市买的)
2.可以"削峰填谷",保证系统的稳定性
阻塞队列就相当于一个缓冲区,平衡了生产者消费者的处理能力
比如在 " 秒杀 " 场景下 , 服务器同一时刻可能会收到大量的支付请求 . 如果直接处理这些支付请求 , 服务器可能扛不住( 每个支付请求的处理都需要比较复杂的流程 ). 这个时候就可以把这些请求都放 到一个阻塞队列中, 然后再由消费者线程慢慢的来处理每个支付请求 .这样做可以有效进行 " 削峰 ", 防止服务器被突然到来的一波请求直接冲垮
2.标准库中的阻塞队列
java标准库中内置了阻塞队列,在使用的时候直接使用标准库中的就行
1.BlockingDeque是一个接口
2.真正实现BlockingDeque的类有三种
3.带有阻塞功能的方法.put()方法用于阻塞队列的入队,take()方法用于阻塞队列的出队.在使用take的时候需要处理异常
public static void main(String[] args) {BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<>();//创建两个线程,来作为生产者和消费者Thread customer = new Thread(() -> {while (true) {try {Integer result = blockingQueue.take();System.out.println("消费元素: " + result);} catch (InterruptedException e) {e.printStackTrace();}}});customer.start();Thread producer = new Thread( () -> {int count = 0;while (true) {try {blockingQueue.put(count);System.out.println("生产元素: " + count );count++;Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}});producer.start();}
上面执行的结果是
上面代码先执行消费元素是因为当customer线程执行到blockingQueue,take()时发生了阻塞,等到producer线程执行blockingQueue.put()后,两个线程并发执行,谁先打印都有可能.
4. 不带阻塞功能的方法 入队列 offer(), 出队列 poll(), 取队首元素 peek().
3.模拟实现阻塞队列
实现阻塞队列的前提是我们要先实现一个普通的队列,实现普通队列的方法有两种,一个是基于链表的队列,采用头删法和尾插法实现一个阻塞队列,另外一个方法是基于数组的循环队列,两个方法的具体实现在下面这篇文章里面.
循环队列的实现.
要模拟实现阻塞队列,前提是在多线程的基础上,通过synchronized关键字对put()和take()方法中的代码进行加锁,然后通过wait()和notify()方法对插入元素和取出元素进行阻塞等待.具体方法是,当插入元素时如果队列满了,就产生阻塞等待,直到有元素取出后唤醒put中的wait().当取出元素的时候,如果队列为空,让take()方法产生阻塞等待,只到有元素插入后,唤醒take()中的wait().
class MyBlockingQueue {private int[] item = new int[1000];private int head = 0;private int tail = 0;private int size = 0;//插入元素public void put(int value) throws InterruptedException {synchronized (this) {while(size == item.length) {//队列满了,产生阻塞等待this.wait();}item[tail] = value;tail++;if(tail >= item.length) {tail = 0;}size++;//唤醒take中的wait()this.notify();}}//取出元素public Integer take() throws InterruptedException {int result = 0;synchronized (this) {while(size == 0) {//队列为空,产生阻塞等待this.wait();}result = item[head];head++;if(head >= item.length) {head = 0;}size--;//唤醒put中的wait()this.notify();}return result;}
}
定时器
定时器就好比是我们生活中的闹钟,当我们被早八的闹钟叫醒后想在床上在躺十分钟,我们设置闹钟就可以让十分钟再响,而我们的计时器具有类似的功能,是指定一段之间后执行一段代码.
在Java的标准库中有一个Timer类,Timer类的核心方法是schedule()
schedule()中有连个参数,第一个参数指定定时器要执行的任务,第二个参数指定多长时间后执行这个任务
模拟实现定时器
主要实现下面几种功能
1.让被注册的任务,能在指定时间后执行.为了实现这个功能可以单独在定时器内部建一个线程,让这个线程周期性的扫描,判断任务时间是否到了,如果到了,就执行,若没动,就继续等待.这n个任务,可以用优先级队列来保存,按照指定时间小的优先级高,就放在队头,此时扫描线程,就只需要扫描队头元素,对头元素时间没到的话,其他时间更不可能到.
在优先级队列中,我们是基于时间进行比较的,可以实现 Comparable接口来进行比较
在扫描线程中会出现下面的bug.
2.一个定时器可以指定N个任务,N个任务会按照指定时间按顺序执行.
具体实现代码
class MyTask implements Comparable<MyTask>{//要执行的任务private Runnable runnable;//任务在什么时间执行(用毫秒时间戳表示)private long time;public MyTask(Runnable runnable, long time) {this.runnable = runnable;this.time = time;}//获取当前任务的时间public long getTime() {return time;}//执行任务public void run() {runnable.run();}@Overridepublic int compareTo(MyTask o) {return (int) (this.time - o.time);}
}//定时器
class MyTimer {//扫描线程private Thread t = null;//有一个阻塞优先级队列private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();public MyTimer() {t = new Thread(() -> {while (true) {try {synchronized (this) {MyTask myTask = queue.take();//取出队头元素观察判断是否到时间了long curTime = System.currentTimeMillis();if(curTime < myTask.getTime()) {//时间没到放回队列queue.put(myTask);} else {//时间到了,执行任务myTask.run();this.wait(myTask.getTime() - curTime);}}} catch (InterruptedException e) {e.printStackTrace();}}} );t.start();}public void schedule (Runnable runnable,long after) {//第一个参数 是指定的任务// 第二个参数是在多少毫秒后执行MyTask myTask = new MyTask(runnable,System.currentTimeMillis()+ after);//把任务放到队列里queue.put(myTask);synchronized (this) {this.notify();}}
相关文章:

阻塞队列和定时器的使用
阻塞队列 谈到队列,大家就能想到队列的先进先出原则,但有些特殊的队列,虽然也是先进先出的,但是带有阻塞功能,我们把这种队列叫做阻塞队列. ★如果队列为空,执行出队操作就会阻塞,阻塞到另外一个线程往队列里添加元素(队列不为空)为止. ★如果队列满了,执行入队操作时,也会阻…...

JavaScript脚本操作CSS
脚本化CSS就是使用JavaScript脚本操作CSS,配合HTML5、Ajax、jQuery等技术,可以设计出细腻、逼真的页面特效和交互行为,提升用户体验,如网页对象的显示/隐藏、定位、变形、运动等动态样式。 1、CSS脚本化基础 CSS样式有两种形式&…...
Rust4.1 Managing Growing Projects with Packages, Crates, and Modules
Rust学习笔记 Rust编程语言入门教程课程笔记 参考教材: The Rust Programming Language (by Steve Klabnik and Carol Nichols, with contributions from the Rust Community) Lecture 7: Managing Growing Projects with Packages, Crates, and Modules src/main.rs // s…...
RPA在财务预测和分析中的应用
在现代企业管理中,财务数据分析是决策制定和战略规划的关键环节。大数据的兴起带来财务数据的复杂性和数量不断增加,企业为此消耗了大量人力和物力。随着当今数字化、智能化时代的到来,越来越多企业引进RPA技术来提高工作效率,实现…...

无人机航拍技术基础入门,无人机拍摄的方法与技巧
一、教程描述 买了无人机,可是我不敢飞怎么办?禁飞区越来越多,到底哪儿才能飞?我的无人机跟你一样,为什么我拍不出大片?厂家的说明书看不进去,有没有一套无人机的课程,可以快速上手…...
PTA 哈密尔回路(建图搜索)
题目 著名的“汉密尔顿(Hamilton)回路问题”是要找一个能遍历图中所有顶点的简单回路(即每个顶点只访问 1 次)。本题就要求你判断任一给定的回路是否汉密尔顿回路。 输入格式: 首先第一行给出两个正整数:…...

如何利用产品帮助中心提升用户体验
在当今竞争激烈的市场中,提供优秀的用户体验是吸引和保留客户的关键。而一个高效和易于使用的产品帮助中心,正成为越来越多企业用以提升用户体验的重要工具。产品帮助中心是一个集中的信息库,为用户提供关于产品功能、故障排除、常见问题解答…...

【Python大数据笔记_day05_Hive基础操作】
一.SQL,Hive和MapReduce的关系 用户在hive上编写sql语句,hive把sql语句转化为MapReduce程序去执行 二.Hive架构映射流程 用户接口: 包括CLI、JDBC/ODBC、WebGUI,CLI(command line interface)为shell命令行;Hive中的Thrift服务器允许外部客户端…...

css呼吸效果实现
实现一个图片有规律的大小变化,呈现呼吸效果,怎么用CSS实现这个呼吸效果呢 一.实现 CSS实现动态效果可以使用动画( animation)来属性实现,放大缩小效果可以用transform: scale来实现,在这基础上有了动画,就可以设置一个…...

机器视觉opencv答题卡识别系统 计算机竞赛
0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 答题卡识别系统 - opencv python 图像识别 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🥇学长这里给一个题目综合评分(每项满分5分…...
2024年的后端和Web开发趋势
目录 1 2 3 4 5 1 不断变化的数字创新格局可能让人感觉像是一场无情的竞赛。作为开发人员,你的痛苦是真实的——交付尖端产品、保持竞争力、跟上不断变化的用户期望,综合起来你的压力可能是压倒性的。 但是,如果我们告诉你有一个指南针…...

对比了10+网盘资源搜索工具,我最终选择了这款爆赞的阿里云盘、百度网盘、夸克网盘资源一站式搜索工具
盘友圈(https://panyq.com)是一个综合性的网盘搜索站,与其他网盘搜索工具相比,它具有多个独特的优点,使其成为用户们首选的平台。 首先,盘友圈汇集了阿里云盘、百度网盘和夸克网盘等主流网盘资源ÿ…...

GoLong的学习之路(二十)进阶,语法之反射(reflect包)
这个是为了接上之前的语法篇的。按照我的学习计划,这里此时应该有一个小项目来做一个统合。但是吧,突然觉得,似乎也没必要。能学go的大部分肯定都是有其他语言的基础的。 接下来说反射 文章目录 反射介绍reflect包TypeOftype name和type kin…...
关于表单校验,:rules=“loginRules“
在写好validator相关的方法后,rule测试没有生效 <el-form ref"loginForm" :model"loginForm" :rules"loginRules" class"login-form" <el-form-item prop"username"> <el-input ref"usernam…...

统一消息分发中心设计
背景 我们核心业务中订单完成时,需要完成后续的连带业务,扣件库存库存、增加积分、通知商家等。 如下图的架构: 这样设计出来导致我们的核心业务和其他业务耦合,每次新增连带业务或者去掉连带业务都需要修改核心业务。 一方面&…...

前端项目导入vue和element
1.安装nodejs 下载链接https://cdn.npmmirror.com/binaries/node/v18.18.0/node-v18.18.0-x64.msi 进入cmd 命令行模式 管理员身份运行 输入 (node -v)能看到版本号 npm config set prefix "C:\Program Files\nodejs" 默认路径 npm config…...

【11】使用透视投影建立一个3D空间的测试
核心操作: 1.proj view model 这三个矩阵 glm::mat4 mvp m_Proj * m_View * model; m_Shader->Bind(); m_Shader->SetUniformMat4f("u_MVP", mvp);着色器里面就: proj:投影矩阵,可以选择正交投影,或者透视投影…...

【广州华锐互动】VR影视制片虚拟仿真教学系统
随着虚拟现实(VR)技术的不断发展,VR在影视制片教学中的应用场景也变得越来越丰富。本文将介绍VR在影视制片教学中的常见应用场景及其意义,并通过案例分析来更好地展示其应用前景。 在影视制片教学中,VR可以提供一种沉浸式的制作体验。其中&am…...

从研发域到量产域的自动驾驶工具链探索与实践
导读 本文整理自 2023 年 9 月 5 日百度云智大会 - 智能汽车分论坛,百度智能云自动驾驶云研发高级经理徐鹏的主题演讲《从研发域到量产域的自动驾驶工具链探索与实践》。 全文中部段落附有演讲中 2 个产品演示视频的完整版,精彩不容错过。 (视频观看&…...
404. 左叶子之和
原题链接:404. 左叶子之和 思路: 首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。 节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...