Java
CleanUp Hitter
学以致用
展开
-
RocketMQ知识点总结
IndexFile(索引文件)提供了一种可以通过key或时间区间来查询消息的方法。Index文件的存储位置是: {fileName},文件名fileName是以创建时的时间戳命名的,固定的单个IndexFile文件大小约为400M,一个IndexFile可以保存 2000W个索引,IndexFile的底层存储设计为在文件系统中实现HashMap结构,故RocketMQ的索引文件其底层实现为hash索引。原创 2024-04-14 21:40:51 · 879 阅读 · 0 评论 -
HashMap扩容源码探究——高低链表的判断过程
我们发现,变化的其实只有第一个1所在的位置,数组长度是2的倍数,而和旧的运算的区别其实就是前面有没有多一个1,我们只需要知道hash的该位置有没有1即可。具体来说,其实就是oldCap化成二进制的那个1所在位置,newCap就是oldCap的1前移了,那么就会导致-1之后&运算之后多了一个1。于是乎,我们也得到了为什么要分高位和地位了,其实就是二进制多了一个1,这个1如果&生效了,其实就相当于在原来的hash基础上+oldCap。链表和红黑树一样,都需要拆成高位和低位,然后移动。在正式看里面运算之前。原创 2024-04-03 10:53:08 · 331 阅读 · 0 评论 -
G1垃圾回收器深入探索——卡表、记忆集和SATB算法
G1的RSet是在Card Table的基础上实现的:每个Region会记录下别的Region有指向自己的指针,并标记这些指针分别在哪些Card的范围内。在GC的时候,对于old->young和old->old的跨代对象引用,不需要扫描整个堆找到谁引用了当前分区中的对象,只要扫描对应的CSet中的RSet即可。在并发标记阶段如果有引用关系被删除,就记录下来,Remark阶段对这些引用关系被删除的重标记,这个破坏了步骤一,即灰色对象断开了白色对象引用的时候,记录下来,后面重新把这个白色对象标记成存活对象。原创 2024-03-23 20:16:20 · 961 阅读 · 0 评论 -
手撕Java集合之简易版Deque(LinkedList)
简易版的双端队列实现。原创 2024-02-28 17:01:09 · 457 阅读 · 0 评论 -
经典单调栈问题——接雨水
从左到右遍历数组,遍历到下标 i 时,发现不满足单调递减。这时候要保证栈内有两个元素,一个作为中间的间隔标识,一个作为左边的支点。这时候先弹出来一个,然后记录下一个栈顶。这时候可以接的雨水为长*宽(左右两端的距离×左边支点和右边支点最小值和弹出来节点的差)。维护一个单调栈,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height 中的元素递减。原创 2024-02-27 10:18:10 · 172 阅读 · 0 评论 -
Java并发编程——伪共享和缓存行问题
由于处理器缓存行的一致性协议要求缓存行中的数据在多个处理器间保持一致,因此当一个线程修改了一个变量并使得缓存行失效后,其他线程即使是访问其他变量也会受到影响。这种情况下,就会出现伪共享。当一个线程访问内存时,会将数据从主内存加载到缓存行中,并且在后续的操作中,只对缓存行进行读写,而不是直接访问主内存。然而,当多个线程同时访问同一个缓存行中的不同变量时,由于缓存行的一致性要求,会导致其他线程的缓存行失效,从而降低性能。填充是在变量之间插入一些无意义的字节,使得不同变量分布在不同的缓存行中,从而避免线程冲突。原创 2024-01-11 20:06:15 · 739 阅读 · 0 评论 -
RocketMQ实现延迟队列
RocketMQ还拥有一些高级特性,例如消息的可靠性投递、消息的顺序性、消息的事务性等。RocketMQ的延迟队列是通过消息的延迟级别来实现的。延迟级别是指消息从发送到被消费之间的时间间隔,可以设置为任意时间段,单位为毫秒。然后创建消息,并设置了延迟级别为2。通过这种方式,可以实现消息的延迟投递,即消息将在指定的延迟时间后才会被消费者消费。在消费者端,可以监听指定的延迟级别来消费延迟消息。请注意,延迟队列只对那些配置了延迟级别的消息生效。构成了延迟级别,它是一个枚举类型,定义了多个级别,例如。原创 2024-01-09 13:04:20 · 776 阅读 · 0 评论 -
CAS的“ABA”问题
这样,CAS操作在比较并交换值时还会比较版本号或时间戳,从而能够判断出是否存在ABA问题。一种常见的解决方案是使用带有标记位的指针,将标记位用于标记指针所指向的数据是否经历了变化。需要注意的是,解决ABA问题需要根据具体的编程语言和场景来选择合适的解决方案。ABA问题指的是,在CAS操作期间,其他线程可能修改了共享数据的值两次,即A->B->A,使得CAS操作能够成功,但。CAS(Compare and Swap)是一种常见的并发控制原语,用于解决多线程环境下的数据竞争问题。原创 2024-01-04 23:45:52 · 418 阅读 · 0 评论 -
synchronized锁的底层原理
在 Java 6 之前,synchronized 锁的实现是重量级锁,使用操作系统的互斥量来实现。在 Java 的内存模型中,每个对象都有一个与之关联的 Monitor 对象,这个 Monitor 对象是用来实现对象的锁机制的。总结起来,synchronized 锁的底层原理是通过对象的 Monitor 锁来实现线程同步,当一个线程获取锁时,会将对象的标志位设置为当前线程的 ID,并将其他线程阻塞,当线程释放锁时,会将标志位清空,并唤醒等待队列中的一个线程继续执行。原创 2024-01-04 18:16:09 · 587 阅读 · 0 评论 -
Java线程池执行流程及参数详解
handler:当线程池中全部线程都在运行,阻塞队列也满的时候,会将添加的任务执行拒绝策略,JDK 线程池中实现了四种拒绝策略,默认 AbortPolicy,并抛出异常。maximumPoolSize:线程池中的最大线程数量,当核心线程都在运行任务,并且阻塞队列中任务数量已满,此时会创建非核心线程。 corePoolSize:线程池中的核心线程数量,如果没有全局设置池内线程的过期时间,池内会维持此数量线程。原创 2023-12-28 14:20:50 · 505 阅读 · 0 评论 -
双指针的运用——双数之和II和三数之和
我们考虑这个排序过的数组,首先一个指针在最左,一个在最右。如果这两个数字比目标数字来的要小,那么如果我们左边指针移动了,移动后一定变大了,所以这么移动OK,如果移动的右边左移那么由于排序的原因只会越来越小,所以根据这个规律双指针移动就一定能找到。这题较难,我们需要先定下三个点一个,然后在以这个点为起点,后面数组在定义两个节点,进行两数之和的过程,中间需要考虑重复的情况,加特判循环略过重复的点。原创 2023-12-13 15:42:11 · 57 阅读 · 0 评论 -
SPI机制——JDBC实现源码中的一个细节
我们知道,JDBC源码中通过SPI文件打破了双亲委派机制并加载了驱动,中间有一个将接口实现类写入META-INF文件的过程,这个过程中会产生这么一个疑问?类的加载是通过读取了这个文件,那这个文件我平时开发也没写过啊。答案就在Maven,Maven工具在构建时候会自动帮助我们写入。原创 2023-12-07 23:07:26 · 77 阅读 · 0 评论 -
Java的List中的各种浅拷贝和深拷贝问题
我们知道ArrayList源码里主要用到了两个拷贝函数分别是Arrays.copyOf()和System.arraycopy()这表明temp是指向的list的地址而不是拷贝了完整的一份是浅拷贝,那么我们如何才能让双方互不影响。先来看看基本数据类型。这里参考ArrayList源码里面的拷贝实现过程。再回到List,我们可以使用Collections.copy实现深拷贝。原创 2023-12-06 15:22:38 · 559 阅读 · 0 评论 -
LRU缓存淘汰策略的实现——LinkedHashMap哈希链表
需要重写removeEldestEntry方法,在缓存容量超过设置的上限时,移除最老的缓存项。哈希表用于快速获取缓存项,而双向链表用于保持缓存项的顺序,最近使用的项在链表的末尾,最少使用的项在链表的开头。:使用put方法向缓存中存入键值对,使用get方法获取指定键对应的值。通过LinkedHashMap的特性,最近访问的缓存项会被移动到链表尾部,从而实现LRU淘汰。LinkedHashMap 是 Java 中提供的一种数据结构,它综合了哈希表和双向链表的特点,非常适合用来实现 LRU 缓存。原创 2023-11-30 19:23:18 · 344 阅读 · 0 评论 -
Spring不再支持Java8了
在今天新建模块的时候发现了没有java8的选项了,结果一查发现在11月24日,Spring不再支持8了,这可怎么办呢?我们可以设置来源为阿里云https://start.aliyun.com/。原创 2023-11-27 18:49:37 · 1400 阅读 · 0 评论 -
Spring原理——基于xml配置文件创建IOC容器的过程
介绍了xml实现IOC的过程。我们通过new一个xml读取类,然后调用其中的方法进行注册容器。在getbean中,实现实例化。我们通过注册类拿到相关的信息,然后利用反射class.forname拿到反射的字节码文件,并利用newInstance方法对Bean实例化。原创 2023-11-24 16:31:16 · 1074 阅读 · 0 评论 -
设计模式——状态模式介绍
在上述示例中,状态模式被用于管理上下文(Context)对象的不同状态。每个具体状态(Concrete State)都实现了状态(State)接口,并根据需要进行状态转换。这对于需要根据状态改变行为的场景非常有用,例如自动售货机中的不同状态(待机、售货、缺货等)的管理。状态模式是一种行为设计模式,它允许对象在内部状态改变时改变它的行为。状态模式的关键组件有三个:上下文(Context)、状态(State)和具体状态(Concrete State)。原创 2023-11-23 09:14:58 · 824 阅读 · 0 评论 -
CGlib动态代理和JDK动态代理
如果被代理类实现了接口,且对性能要求不高,可以选择JDK动态代理。JDK动态代理使用Java的反射机制来实现代理功能,通过Proxy类和InvocationHandler接口来生成代理对象,并在代理对象的方法调用时,通过InvocationHandler的invoke方法来执行相应的逻辑。CGlib通过继承被代理类,生成一个代理类的子类,并重写父类的方法,在方法的前后插入相应的代理逻辑。与之相对,JDK动态代理是基于接口的代理模式,它通过生成一个实现了被代理接口的代理类来实现代理功能。原创 2023-11-19 12:36:02 · 126 阅读 · 0 评论 -
观察者模式的运用——消息队列
对象不需要直接知道观察者对象的存在,也不需要关心观察者对象的处理逻辑,只需要将消息发布到队列中即可。RocketMQ思路起源于Kafka,但并不是Kafka的一个Copy,它对消息的可靠传输及事务性做了优化,目前在阿里集团被广泛应用于交易、充值、流计算、消息推送、日志流式处理、binglog分发等场景。Kafka中的消息由键、值、时间戳组成,kafka不记录每个消息被谁使用,只通过偏移量记录哪些消息是未读的,kafka中可以指定消费组来实现订阅发布的功能。原创 2023-11-17 21:58:27 · 372 阅读 · 0 评论 -
反射和序列化操作会破坏单例模式
另一方面,序列化和反序列化操作可以破坏单例模式,因为它们允许创建具有与原始单例实例相同状态的新对象。为避免这种情况发生,可以在单例类中实现 readResolve() 方法,并在其中返回已经存在的单例实例。使用反射可以访问类的私有构造函数并强制创建一个新的实例,这将破坏单例模式的唯一性原则,因为它允许创建多个实例。为防止这种情况发生,可以通过在单例类的构造函数中添加防止多次实例化的检查来进行保护。方法在反序列化过程中被调用,确保返回的是单例实例,从而避免通过序列化创建新的实例。在构造函数中,我们通过检查。原创 2023-11-17 17:16:22 · 577 阅读 · 0 评论 -
Mybatis-Plus的IPage和Page
IPage 是 Mybatis-Plus 中的分页结果集接口,它继承了 Mybatis 的 RowBounds 接口,提供了一系列的分页查询方法。该接口主要用于返回分页后的数据结果。Page 类是 IPage 接口的默认实现类,实现了 IPage 接口中的方法。在进行分页查询时,通常会创建一个 Page 对象,并设置相关的分页参数。在这个例子中,我们通过构造一个 Page 对象来设置当前页和每页条数。Mybatis-Plus 中的分页查询接口主要有两个:IPage 和 Page。原创 2023-11-14 15:06:59 · 2948 阅读 · 0 评论 -
阿里云OSS和腾讯云COS对象存储介绍和简单使用
阿里云的OSS对象存储是基于阿里云平台提供的一种分布式对象存储服务,OSS的API调用简单明了,支持多种的客户端/SDK,极大的方便了开发人员对数据进行访问。使用阿里云的OSS对象存储,除了具备高效的访问性能、数据可靠性和强大的扩展性外,还可以通过授权访问、日志记录等功能实现高可靠高安全性的数据存储与管理。,其主要是将数据以对象的形式存储在云端,并且提供了完全的API调用,这些API包括上传,下载,删除,复制,预览,权限设置等等。腾讯云的COS对象存储也是一种可靠、耐用、安全的云对象存储服务。原创 2023-11-12 12:14:32 · 1181 阅读 · 0 评论 -
SpringGateWay——yml文件配置详解
discovery 字段表示启用服务发现功能,该配置项通常与注册中心配合使用,可以自动从注册中心获取可用的服务列表。上面的配置文件中,routes 是一个路由列表,每一个路由配置包括 ID、目标服务地址、路由条件和过滤器等。其中,predicates 指定了路由条件,可以通过 Path、Method、Header、Host、RemoteAddr 等条件进行匹配。Spring Gateway 是一个基于 Spring 框架的网关服务,主要作用是将流量路由到不同的微服务中。原创 2023-11-12 12:07:27 · 1768 阅读 · 0 评论 -
UrlBasedCorsConfigurationSource无法转换为CorsConfigurationSource的原因
cors.reactive和cors中都有UrlBasedCorsConfigurationSource,如果照着尚硅谷老师的思路去做而不是直接复制代码,非常容易出现该问题。原创 2023-11-10 19:09:16 · 312 阅读 · 0 评论 -
Java设计模式——责任链模式
在该模式中,每个处理者都能够决定自己是否要处理请求,并在必要时将请求传递给链上的下一个处理者。Handler 是处理者对象的抽象类,定义了抽象方法 handleRequest 用于处理请求,同时提供了一个引用 successor 用于表示链上的下一个处理者。从结果可以看出,请求 Request 1 和 Request 2 被正确的处理了,而请求 Request 3 则没有被任何一个处理者处理。每个具体的处理者对象都会处理特定类型的请求,如果自己不能处理该请求,则将请求转发给下一个处理者。原创 2023-11-10 13:30:24 · 482 阅读 · 0 评论 -
配置中心和注册中心——Nacos
Nacos支持配置的动态刷新和动态发布,当配置信息发生变化时,Nacos会自动通知应用程序更新配置。Nacos作为注册中心,可以用于服务发现和服务注册与注销。当有新的服务实例启动时,它们会向Nacos注册自己的信息,包括服务名、IP地址、端口号等。Nacos支持灵活的服务路由和负载均衡策略,可以实现动态的服务发现和服务治理。Nacos作为一个功能强大的服务基础设施平台,可以用于实现微服务架构中的服务注册、服务发现和动态配置管理等核心功能,帮助开发人员构建弹性、可扩展和可靠的分布式系统。原创 2023-11-09 13:25:53 · 145 阅读 · 0 评论 -
Java——Stream流的peek方法
请注意,peek()方法的作用不是为了改变流中的元素,因此您应该避免在peek()方法中进行任何有副作用的操作。在Java 8中,Stream的设计旨在提供一种非常简洁、简单且易于使用的方式来处理数据,而不是作为一个逐步构建的可变状态的构建器,因此我们应该遵循设计的原则和实践。Java Stream中的peek()方法也是用于查看每个元素,但不改变流的操作的方法。在执行过程中,peek()方法会打印出相应的调试信息,但并不会修改流中的元素。最后,我们将转换后的大写字符串添加到了新的List中。原创 2023-11-09 13:20:21 · 4367 阅读 · 0 评论 -
Docker介绍及其常用命令
它实现了操作系统级别的虚拟化,允许不同容器之间相互隔离,同时提高了应用程序的可移植性和安全性。Docker生态系统非常丰富,包括许多第三方工具和服务,提供了镜像管理、容器编排、安全性和可扩展性等功能,进一步简化了容器的使用和管理。总之,Docker是一种功能强大的容器化技术,它实现了操作系统级别的虚拟化,允许开发人员将应用程序和其依赖项打包到一个可移植的容器中。通过使用Docker,开发人员可以快速部署和扩展应用程序,同时提高了应用程序的可移植性和安全性。该命令用于列出本地所有的镜像。原创 2023-11-05 11:49:38 · 568 阅读 · 0 评论 -
Java序列化和Json格式的转化
Java 序列化的格式通常是不可读的二进制格式,它的主要优点是可以保留对象中的所有信息,包括类名、字段名称、类型和方法等。但是,由于 Java 序列化的格式不是开放标准,因此只能在 Java 环境中使用,并且在不同版本的 Java 中可能存在不兼容的问题。Java 序列化和 JSON 格式的转化可以通过许多 Java 库和框架实现,例如使用 Jackson 库将 Java 对象转换为 JSON 格式,或使用 GSON 库将 JSON 格式的数据反序列化为 Java 对象。原创 2023-11-05 10:28:30 · 999 阅读 · 0 评论 -
详解Java经典数据结构——HashMap
内部实现:HashMap 的实现逻辑基于数组和单向链表,每个数组元素都是一个链表的头节点,当发生 Hash 冲突时,新插入的键值对会添加到对应元素的链表中。在 JDK9 中,HashMap 对链表的处理进行了更改,引入了一个新节点类型-Node,用于兼容红黑树节点和链表节点。基本结构:HashMap 底层是基于哈希表来实现的,每次插入一个键值对时,会先对该键进行 Hash 运算,然后将值保存在对应的索引位置上,这个索引就是通过哈希函数计算出来的。原创 2023-11-01 13:16:14 · 277 阅读 · 0 评论 -
什么是Java线程池?如何实现?
使用线程池可以减少线程的创建和销毁开销,并确保一定数量的线程可用来执行任务,以避免资源耗尽和线程过多导致的性能问题。ExecutorService接口:继承自Executor接口,定义了一组管理线程池的方法,比如提交任务、关闭线程池等。Executor接口:定义了一个执行任务的方式,它是线程池的顶层接口。创建一个线程池对象,可以使用Executors工厂类提供的方法来创建常用的线程池。线程池会自动调度线程来执行任务,当任务执行完毕后,线程会自动返回线程池以供重用。,用于提交一个任务给线程池执行。原创 2023-10-31 12:25:11 · 37 阅读 · 0 评论 -
什么是单一职责原则?
单一职责原则(Single Responsibility Principle,SRP)是面向对象设计中的一个重要原则,它建议一个类应该只有一个引起变化的理由,也就是说,一个类应该只有一个职责。如果未来需要更改文件读取或写入的逻辑,只需修改相应的类,而不会影响另一个职责。,它既负责文件的读取,又负责文件的写入。通俗地说,单一职责原则就是一个类不应该承担太多不同的职责,因为这会增加类的复杂性,降低代码的可维护性。为了遵守单一职责原则,我们可以将这个类分割为两个单独的类:一个负责文件读取,另一个负责文件写入。原创 2023-10-26 19:57:46 · 27 阅读 · 0 评论 -
如何进行Mysql查询语句优化?
优化查询语句的写法,例如合理使用 WHERE 子句、使用 LIMIT 限制结果集大小、避免使用不必要的子查询等。分析和优化慢查询:通过使用 EXPLAIN 命令,分析查询语句的执行计划,查看索引使用情况和性能瓶颈。使用缓存:利用 MySQL 自带的查询缓存功能,缓存频繁查询的结果。避免频繁的表连接和子查询:合理设计数据库结构,尽量减少表连接的次数和子查询的嵌套层次。优化表结构:根据查询的需求,合理设计表的结构,选择合适的数据类型和字段长度,避免使用过多的冗余字段和重复数据。原创 2023-10-22 22:17:57 · 28 阅读 · 0 评论 -
JVM垃圾回收GC——三色标记法
垃圾回收器首先将所有的对象标记为白色,然后从根对象(如活动线程、全局变量等)开始,通过深度优先搜索算法遍历对象引用链,并将可达的对象标记为黑色。JVM的三色标记法是一种高效的垃圾回收算法,能够准确地标记和清除不再使用的对象,从而释放内存资源。当一个对象被标记为灰色时,它的引用链上的对象尚未被扫描和分析,即引用链上的其他对象还未确定是否可达。黑色:表示对象已经被标记为可达性分析的一部分,即该对象是可达的,其引用链上的所有对象都已经被垃圾回收器扫描过。白色:表示对象尚未被扫描和分析,即还未确定是否可达性。原创 2023-10-11 23:12:01 · 140 阅读 · 0 评论 -
优惠券秒杀逻辑总结
其实如果加的锁是业务名字+用户ID的话不管单例还是集群都会出现锁的误删,单例中没有考虑主要是因为有synchronized锁和乐观锁把所有问题解决了,没有用到Redis锁,锁的时候根本不看名字的,但是集群中哪怕对比线程ID都会出意外,两个计算机可能会有相同的线程ID访问同一个业务就会出现问题。首先,分布式锁先要考虑一个问题就是分布式锁一定要所有服务都能访问一把锁,这把锁就可以是Redis的锁,Redis是单线程直接存在线程之中访问快能够最大程度上提升整体的访问效率。一人一单,一个人只能下一单。原创 2023-09-27 16:48:07 · 132 阅读 · 0 评论 -
为什么可以使用Lua脚本+Redis解决分布式系统下的多线程访问问题(经典超卖问题)
2、Redis具有单线程特性,多个实例的Lua脚本同时过来只能一个一个执行,不能多个一起执行,这样也保证了数据安全。1、首先Lua脚本有原子性,这就保证了在一个实例上,只能有一个线程进来访问,不会出现多线程问题。在判断用户可以买了之后直接把消息扔到队列里等待异步处理即可。原创 2023-09-26 22:42:30 · 187 阅读 · 0 评论 -
登陆方式session/token+redis/jwt
JWT登录的优势在于,可以实现无状态认证,避免服务器存储会话信息,减轻服务器的负担,并将用户信息放在Token中,减少数据库查询。更新Token的方式可以是生成一个新的Token,将其作为新键,将旧Token对应的用户信息作为值存储在Redis中,然后将新Token返回给客户端。更新Token的方式可以是生成一个新的Token,替换旧的Token。使用Token和Redis进行登录的好处是,服务器无需保持用户的状态信息,将用户信息存储在Redis中可以有效减轻服务器的负担,并支持分布式应用程序的扩展。原创 2023-09-20 19:17:55 · 409 阅读 · 0 评论 -
Java分页器如何让返回的pageData增加参数
原因在于Headline类中不包含pasthours,那么在定义分页器时 Ipage中不能直接放进去headline不然会少参数,那么怎么办呢?这是尚硅谷微头条教案中的一个部分,但是我写完后发现前端页面并不能正确显示过去的时间。将定义改为Map 即Ipage。原创 2023-09-17 16:29:43 · 103 阅读 · 0 评论 -
乐观锁和悲观锁
在实际应用中,有时也会将乐观锁和悲观锁结合使用,在具体操作前使用乐观锁进行快速检查,若检查失败再回退到悲观锁进行具体的处理。悲观锁的优点是可以确保数据的一致性,避免了数据冲突的可能性。因此,悲观锁适用于写多读少的场景或对数据一致性要求较高的情况。乐观锁的优点是没有显式的锁冲突,对于读多写少的场景可以提高并发性能。在学习Java时,我们常常会听到乐观锁和悲观锁,那么什么是乐观锁,什么是悲观锁呢?乐观锁和悲观锁是并发控制的两种不同策略,用于处理多个并发操作对共享资源的访问问题。T1和T2并发执行。原创 2023-09-14 18:40:19 · 24 阅读 · 0 评论 -
Mybatis的${}和#{},${}数据库注入问题
如果数据库中所有人的年龄都大于等于1我们就得到了所有人的id,所以直接插入可能会导致很多问题。取值符号不会自动为String加上‘’单引号。取值符号会自动为String类型的参数加上‘’单引号、会给字符串类型加引号,所以在遇到数据库的字段例如。可能会出现数据库注入。原创 2023-09-08 20:45:15 · 156 阅读 · 0 评论