手撕—LFU
与LRU不同,LRU是根据访问顺序来淘汰,LFU是根据访问频率淘汰最少使用的节点
思路使用一个哈希表作为key到具体Node的映射,快速定位节点
再使用一个哈希表存储同使用频率的Node,同频率的节点按时间顺序存储,方便淘汰最早插入的
再使用一个minFreq变量,记录当前最小的频率
实现class Node{ // 节点类,记录当前kv和频率 int key, value, freq; public Node(int key, int value){ this.key = key; this.value = value; freq = 1; }}class LFUCache { private int capacity, minFreq; private Map<Integer, Node> keyMap; // key对应节点的哈希表 private Map<Integer, LinkedHashSet<Node>> ...
手撕—实现JSON字符串解析
来源:字节一面
题目实现一个方法,找到json字符串的对应路径的值。我们假设json中没有复杂结构,只存在数字、字符串。
输入:一个Json格式的字符串和一个路径字符串
输出:对应路径的值
例子:
输入:”{“a”:{“b”:1},”c”:1}” “a.b”
输出:1
解析分析:主要考字符串处理和递归,主要思路为将输入的字符串转化成哈希表,便于查找,然后递归进行哈希表键值对的插入,然后处理路径,一层一层找即可。
import java.util.*;public class Main{ public static Map<String, Object> parseJson(String json) { // 字符串处理,去掉前后空格和大括号 json = json.trim(); Map<String, Object> map = new HashMap<>(); json = json.substring(1, json.length() - 1).trim() ...
手撕—带过期时间的LRU
与传统的LRU类似,使用双向链表+哈希表来完成
双向链表按照被使用顺序存储键值对,靠近头部的键值对是最近使用的,哈希表通过缓存数据的键映射到其在双向链表中的位置
对于get操作,首先判断key是否存在,如果key存在,再判断key是否过期,如未过期,则key对应的节点是最近被使用的节点。通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部,最后返回该节点的值
对于put操作,首先清理所有过期的节点,再判断key是否存在,如果key不存在,使用key和value创建一个新的节点,在双向链表的头部添加该节点,并将key和该节点添加进哈希表中。然后判断双向链表的节点数是否超出容量,如果超出容量,则删除双向链表的尾部节点,并删除哈希表中对应的项。如果key存在,先通过哈希表定位,再将对应的节点的值更新为value,并将该节点移到双向链表的头部
以系统时间为基准// 双向链表节点类class DLinkedList{ int key; int value; long expireTime; DLinkedList pre; DLi ...
手撕—单例模式
这里有两种实现方式,双重检查锁定(DCL)或静态内部类
DCLpublic class Singleton { // volatile保证可见性和禁止指令重排序 private static volatile Singleton instance; // 私有构造方法 private Singleton() { // 防止反射攻击 if (instance != null) { throw new RuntimeException("Use getInstance() method to get the single instance"); } } public static Singleton getInstance() { // 第一次检查,避免不必要的同步 if (instance == null) { synchronized ...
SpringSecurity基础入门
Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架
SpringSecurity配置示例@Configuration@EnableWebSecuritypublic class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(AbstractHttpConfigurer::disable) // 关闭CSRF .authorizeHttpRequests(auth -> auth .requestMatchers("/login", "/register").permitAll() .anyRequest().authenticated() ) .f ...
JUnit与Mockito测试框架入门
软件测试测试过程按照阶段划分可以分为:
单元测试:对程序模块进行输出正确性检验
集成测试:在单元测试基础上,整合各个模块组成子系统,进行集成测试
系统测试:将整个交付所涉及的协作内容都纳入其中考虑,包含硬件、软件、接口、操作等等一系列作为一个整体,检验是否满足软件或需求说明
验收测试:在交付或者发布之前对所做的工作进行测试检验
单元测试单元测试是阶段性测试的首要环节,也是白盒测试的一种,该内容的编写与实践可以前置在研发完成,研发在编写业务代码的时候就需要生成对应代码的单元测试。单元测试其实是针对软件中最小的测试单元来进行验证的。这里的单元就是指相关的功能子集,比如一个方法、一个类等。值得注意的是作为最低级别的测试活动,单元测试验证的对象仅限于当前测试内容,与程序其它部分内容相隔离
单元测试有以下特征:
主要功能是证明编写的代码内容与期望输出一致
最小最低级的测试内容,保证程序基本组件正常
单元测试尽量不区分类与方法,主张以过程性的方法为测试单位
专注于测试一小块的代码,保证基础功能
剥离与外部接口、存储之间的依赖,使单元测试可控
任何时间任何顺序执行单元测试都需 ...
OSS与优化基础入门
OSS(Object Storage Service)是阿里云提供的海量、安全、低成本的云存储服务,用于存储和管理任意类型的文件(如图片、视频、文档等)
特点:
无限容量:按需扩展,无需提前规划存储空间
高可靠性:数据多副本存储,保障持久性
低成本:按实际使用量付费,无闲置费用
高并发访问:支持CDN加速,适合大流量场景
能解决什么问题?
文件存储与管理:替代自建文件服务器,避免运维成本
静态资源托管:存储网站图片、视频等静态资源,提升加载速度
备份与归档:长期保存日志、数据库备份等冷数据
跨地域访问:结合CDN实现全球加速
OSS的组成OSS的存储结构相当于windows的盘符中,不创建文件夹,而是把所有文件都堆到一块
Bucket (存储桶)在初始化oss容器时就需要指定,在OSS全局命名空间中必须有唯一名称,支持私有(只有Bucket拥有者可以读写,其他用户无权限)、公共读(Bucket拥有者可读写,匿名用户可读,知道对象URL即可下载)、公共读写(Bucket拥有者可读写,匿名用户可读写,可上传/删除/覆盖对象)三种ACL权限
相当于文件系统中的” ...
面试问题汇总(持续更新中)
你项目中用到了哪些设计模式在线程池的创建,Zookeeper客户端的创建使用到的单例模式,避免重复创建
创建序列化器,编解码器用到了工厂模式,根据用户配置创建不同的序列化方式
在实现不同序列化方式的时候用到了策略模式,把不同序列化方式封装成一个策略,实现统一接口
小程序项目中使用注解+AOP实现权限控制,本质是基于代理方法在方法调用前做拦截,用到了代理模式
在RPC框架中注册中心监听节点变化用到了观察者模式
Spring中用到了哪些设计模式Bean的创建是单例的,用到了单例模式
Bean的管理使用的BeanFactory,用到了工厂模式
Bean的注入用到了原型模式,每次注入新实例
通用逻辑的封装,比如JdbcTemplate,用到了模板方法模式
Spring事件监听机制用到了观察者模式
SpringMVC的拦截器、过滤器链用到了责任链模式
Bean的生命周期管理用到了状态模式
AOP用到了代理模式
SpringMVC的HandlerAdapter适配不同Controller用到了适配器模式
ES的基本原理ES中比较关键的概念有索引,相当于MySQL的表,文档,相当于表中的行,字段,相 ...
xxl-Job基础入门
分布式任务调度我们可以思考一下下面业务场景的解决方案:
某电商平台需要每天上午10点,下午3点,晚上8点发放一批优惠券
某银行系统需要在信用卡到期还款日的前三天进行短信提醒
某财务系统需要在每天凌晨0:10分结算前一天的财务数据,统计汇总
以上场景就是任务调度所需要解决的问题
任务调度是为了自动完成特定任务,在约定的特定时刻去执行任务的过程
为什么需要分布式调度使用Spring中提供的注解@Scheduled,也能实现调度的功能,在业务类中方法中贴上这个注解,然后在启动类上贴上@EnableScheduling注解
@Scheduled(cron = "0/20 * * * * ? ") public void doWork(){ //doSomething }
但是这种方式:
只能在一台机器上运行,如果程序或者系统出现异常就会导致功能不可用
在单机模式下,定时任务是没什么问题的。但当我们部署了多台服务,同时又每台服务又有定时任务时,若不进行合理的控制在同一时间,只有一个定时任务启动执行,定时执行的结果就可能存在混乱和错误了
原本 ...
项目常见问题梳理(持续更新中)
RPC项目为什么要做RPC项目目前的应用大部分都是分布式或者微服务架构,通常各个模块之间都是通过rpc来进行调用的,所以我认为自己写一个rpc项目可以更加深入的理解rpc的原理
然后在写rpc项目的过程中,学会了对Zookeeper和netty的使用,也学会了通信协议设计、序列化算法、服务注册与发现、负载均衡策略的设计和使用。
项目有什么难点,如何解决的
关于通信协议的实现和切换模块,我希望客户端和服务端支持http,socket和netty传输协议,并且根据配置自动切换。我的解决方案是首先定义了统一的接口RpcClient 和 RpcServer,然后实现其协议子类比如NettyRpcServer和HttpRpcServer,利用Spring Boot的 @ConditionalOnProperty和@ConditionalOnMissingBean 机制,支持配置项自动装配对应的协议实现
关于负载均衡模块的实现,就是服务调用时如何在多个服务节点直接选择一个合适的目标节点。我的解决方案是定义一个统一的接口LoadBalance,在此基础上扩展成随机、轮询和一致性哈希三种方法,使用SP ...