当前位置: 首页 > news >正文

Java,八股,cv,算法——双非研0四修之路day23

目录

 昨日总结

今日计划

算法——逆波兰表达式

 算法——滑动窗口最大值(逆天的单调队列解法)

JVM

分布式缓存

Redis持久化

Redis主从集群

Redis哨兵

Redis分片集群结构

昨日八股答案 

今日八股


 昨日总结

  • redis高级篇(分布式缓存),JVM课程学习
  • cv(停滞中)
  • 背诵小林coding--Java并发面试篇(6/6)
  • 代码随想录——逆波兰表达式,滑动窗口最大值逆天的单调队列解法

今日计划

  • redis高级篇(分布式缓存+多级缓存),JVM底层原理
  • cv(停滞中)
  • 背诵小林coding--Java并发面试篇(1/5)
  • 代码随想录——前k个高频元素,二叉树的递归与非递归遍历

算法——逆波兰表达式

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
class Solution {public int evalRPN(String[] tokens) {//思路一点没有,全是语法错误。注意:push操作最好在case中完成,不要单拿出来。而且不要一上来就取栈的元素,否则可能//会抛出NoSuchElementException异常。//初始一个栈,方便出栈计算//Stack 类是一个泛型类,它只能存储引用类型,而 int 是基本数据类型,需要借助自动装箱机制将 int 转换为其对应的包装类 Integer 来实现入栈操作。Deque<Integer> stack = new LinkedList<Integer>();for(String index : tokens) {int one,two,res = 0;switch(index) {case "+" :one = stack.pop();two = stack.pop();res = two + one;stack.push(res);break;case "-" :one = stack.pop();two = stack.pop();res = two - one;stack.push(res);break;case "*" :one = stack.pop();two = stack.pop();res = two * one;stack.push(res);break;case "/" :one = stack.pop();two = stack.pop();res = two / one;stack.push(res);break;default :stack.push(Integer.valueOf(index));break;}}return stack.pop();}
}

 算法——滑动窗口最大值(逆天的单调队列解法)

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 

示例 :

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
//利用双端队列手动实现单调队列
/*** 用一个单调队列来存储对应的下标,每当窗口滑动的时候,直接取队列的头部指针对应的值放入结果集即可* 单调队列类似 (tail -->) 3 --> 2 --> 1 --> 0 (--> head) (右边为头结点,元素存的是下标)*/
class Solution {public int[] maxSlidingWindow(int[] nums, int k) {ArrayDeque<Integer> deque = new ArrayDeque<>();int n = nums.length;int[] res = new int[n - k + 1];int idx = 0;for(int i = 0; i < n; i++) {// 根据题意,i为nums下标,是要在[i - k + 1, i] 中选到最大值,只需要保证两点// 1.队列头结点需要在[i - k + 1, i]范围内,不符合则要弹出while(!deque.isEmpty() && deque.peek() < i - k + 1){deque.poll();}// 2.既然是单调,就要保证每次放进去的数字要比末尾的都大,否则也弹出while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {deque.pollLast();}deque.offer(i);// 因为单调,当i增长到符合第一个k范围的时候,每滑动一步都将队列头节点放入结果就行了if(i >= k - 1){res[idx++] = nums[deque.peek()];}}return res;}
}

JVM

  • JVM中表示两个class对象是否为同一个类:首先类的完整类名必须一致,包括包名;加载这个类的ClassLoader必须相同,否则这两个类的对象是不相等的
  • JVM必须指到一个类型是由启动加载器加载的还是用户类加载器加载的。一是因为采用双亲委派机制,需要保证类的加载顺序。二是防止与启动类加载器的核心类库同名,防止核心类被篡改。
  • 灰色区域是每个线程独立拥有的,红色是每个进程(虚拟机实例)对应一份,同时红色也是线程共享的部分
  • JVM的垃圾回收主要集中在堆区和方法区,栈是没有GC(垃圾回收)的,他垃圾回收就是进站出站。
  • PC没有GC,也没有OOM(内存不足异常)
  • 栈是运行时的单位(程序如何运行,如何处理数据等等问题),堆是存储的单位(数据的存储问题,数据怎么放,放在哪等)
  • 栈存在OOM内存溢出,但不存在GC

分布式缓存


Redis持久化

  1. RDB异步持久化:
bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB文件。
fork操作就是在复制页表(与操作系统知识紧密相关)
缺点: RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险。fork紫禁城、压缩、写出RDB文件都比较耗时
  1. AOF持久化:
redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。

Redis主从集群

数据同步原理
全量同步流程图
全量同步的流程
  • slave节点请求增量同步
  • master节点判断replid,发现不一致,拒绝增量同步
  • master将完整内存数据生成RDB,发送RDB到slave
  • slave清空本地数据,加载master的RDB
  • master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
  • slave执行接收到的命令,保持与master之间的同步
增量同步流程图
注意:repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。
主从集群就数据同步问题的优化
  1. 在master中配置repl-diskless-syncyes启用无磁盘复制,避免全量同步时的磁盘lO。
  2. Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
  3. 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
  4. 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
总结
全量与增量同步区别
  • 全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。
  • 增量同步:slave提交自己的offset到master,master获取repL_baklog中从offset之后的命令给slave
什么时候执行全量同步
  • slave节点第一次连接master节点时
  • slave节点断开时间太久,repl_baklog中的offset已经被覆盖时
什么时候执行增量同步
  • slave节点断开又恢复,并且在repl_baklog中能找到offset时

Redis哨兵

背景:在redis主从集群中如果主节点发生了宕机,可以采用Redis哨兵来实现主从集群的自动故障恢复。
作用:
  • Sentinel监控主从节点是否正常工作
  • 如果主节点发成故障,Sentinel将一个从节点升为主节点。故障恢复后,也以新的主节点为主
  • 通知客户端节点地址发生变更,通过访问Sentinel来查询是否发生变更。(RedisTemplate已经实现了查询节点是否变更的更新,只需调用即可,其中还可配置主从读写分离操作)

Redis分片集群结构

背景:单主从和哨兵可以解决高可用、高并发读的问题,但无法解决高 并发写和海量数据存储的问题,因此分片集群结构来解决
特征
  • 集群中有多个主节点,每个主节点保存不同的数据
  • 每个主节点(master)都可以有多个从节点
  • 主节点之间通过ping检测彼此的健康状态
  • 客户端请求可以访问集群任意节点,最终都会被转发到正确节点

昨日八股答案 

  • Voliatle关键字的作用,可以保证线程安全吗

Voliatle可以保证各线程的可见性。类似于全局变量,他的修改,在局部方法中都会看到他的变化。当一个线程修改了volatile修饰的变量的值,其他线程能够立即看到最新的值,从而避免了线程之间的数据不一致。

但是他无法保证线程的安全性,需要sunchronized或锁机制来实现原子性和安全性的保证。

  • Voliatle与Synchronized的比较

Synchronized是一种互斥行的同步机制,保证资源限制一个线程去访问。

Voliatle是一种轻量级的同步机制,同上。也防止指令重排序。。

  • 介绍一下线程池工作的原理

工作的原理是根据线程池的容量,来判断任务的执行。

大概得工作流程是:当任务发出后,需要判断线程池是否在运行,否则拒绝任务,是则下一步判断。判断剩余线程数是否还有空间,是则添加线程并执行任务,否则进入阻塞队列的判断。阻塞队列也满,则进入最大线程数的判断,未满,则进入阻塞队列;如果达到了最大线程数,则拒绝任务。否则执行任务。

今日八股

  • JVM的内存模型架构

  • JVM中堆栈的区别

  • JVM方法区中方法的执行过程

  • 程序计数器的作用,为什么是私有的

http://www.dtcms.com/a/311963.html

相关文章:

  • SpringBoot 信用卡检测、OpenAI gym、OCR结合、DICOM图形处理、知识图谱、农业害虫识别实战
  • 博客|基于Springboot的个人博客系统设计与实现(源码+数据库+文档)
  • 占道经营识别漏检率↓76%:陌讯动态场景适配算法实战解析
  • 区分「尊重」和「顺从」
  • FastAPI入门:响应模型
  • 如何分析Linux内存性能问题
  • Windows字体simsum.ttf的安装与Python路径设置指南
  • junit中@InjectMocks作用详解
  • wgd v1.1.2 安装与使用-生信工具056
  • Java 字符串常量池 +反射,枚举和lambda表达式
  • 【数据结构】栈的顺序存储(整型栈、字符栈)
  • Postman四种请求教程
  • unsloth - LLM超级轻量级微调框架
  • ollama 多实例部署
  • 语音识别数据集
  • 【ROS2】ROS2节点Node机制与常用命令行
  • Autosar Nm-网管报文PNC停发后无法休眠问题排查
  • 决策树算法:三大核心流程解析
  • Agents-SDK智能体开发[4]之集成MCP入门
  • Qt 槽函数被执行多次,并且使用Qt::UniqueConnection无效【已解决】
  • Python编程基础与实践:Python文件处理入门
  • 智能手表:MPU6050和水平仪,动态表情包
  • 第14届蓝桥杯Python青少组中/高级组选拔赛(STEMA)2023年1月15日真题
  • Qemu-NUC980(二):时钟clock代码添加
  • 驾驶场景玩手机识别:陌讯行为特征融合算法误检率↓76% 实战解析
  • 如何修复非json数据
  • 兰空图床部署教程
  • 从C++0基础到C++入门(第十五节:switch语句)
  • 工具包:位图格式一键生成可无限放大的矢量图SVG/EPS及CAD文件DXF
  • 我的世界模组开发教程——物品item(1)