三友的java日记

其他

Redis分布式锁真的很安全吗?

Martin,是英国剑桥大学的一名分布式系统研究员。在此之前他曾是软件工程师和企业家,从事大规模数据基础设施相关的工作。它还经常在大会做演讲,写博客,写书,也是开源贡献者。他马上写了篇文章,质疑这个
1月29日 下午 9:48
其他

万字+20张图探秘Nacos注册中心核心实现原理

大家好,我是三友~~今天就应某位小伙伴的要求,来讲一讲Nacos作为服务注册中心底层的实现原理不知你是否跟我一样,在使用Nacos时有以下几点疑问:临时实例和永久实例是什么?有什么区别?服务实例是如何注册到服务端的?服务实例和服务端之间是如何保活的?服务订阅是如何实现的?集群间数据是如何同步的?CP还是AP?Nacos的数据模型是什么样的?...本文就通过探讨上述问题来探秘Nacos服务注册中心核心的底层实现原理。虽然Nacos最新版本已经到了2.x版本,但是为了照顾那些还在用1.x版本的同学,所以本文我会同时去讲1.x版本和2.x版本的实现观前提醒,本文又又又是一篇超长的干货,非常适合一键三连~~临时实例和永久实例
1月2日 下午 9:48
其他

1.5万字 + 25张图盘点RocketMQ 11种消息类型,你知道几种?

大家好,我是三友~~故事的开头是这样的最近有个兄弟私信了我一张截图我一看截图内容,好家伙,原来是我一年多前立的flag倒不是我忘了这件事,我后来也的确写了一篇的关于RocketMQ运行的原理的文章只不过这篇文章是从上帝的视角去看待RocektMQ一条消息整个生命周期的过程所以就没有具体的分析事务和延迟消息的实现原理,也算是留下了一个小小的坑吧不过,既然现在有兄弟问了,那么今天我这就来把这个坑填上并且,索性咱就直接把这个坑填得满满的,直接盘点RocketMQ支持的11种消息类型以及背后的实现原理本文是基于RocketMQ
2023年11月7日
其他

万字+20张图剖析Spring启动时核心的12个步骤

这个方法其实也比较简单,就是将监听器给添加到ApplicationEventMulticaster中finishBeanFactoryInitialization
2023年9月11日
其他

三万字盘点Spring 9大核心基础功能

大家好,我是三友~~今天来跟大家聊一聊Spring的9大核心基础功能。其实最近有小伙伴私信问我怎么不写文章了,催更来了其实我不是不写,而是一直在写这篇文章,只不过令我没想到的是,从前期的选题、准备、翻源码、动手到写完,前后跨度接近一个月的时间,花了好几个周末,写了三万字,最终才算完成。所以如果本篇文章对你有所帮助,还请多多点赞、转发、在看,非常感谢!!话不多说,先上目录友情提示,本文过长,建议收藏,嘿嘿嘿!资源管理资源管理是Spring的一个核心的基础功能,不过在说Spring的资源管理之前,先来简单说一下Java中的资源管理。Java资源管理Java中的资源管理主要是通过java.net.URL来实现的,通过URL的openConnection方法可以对资源打开一个连接,通过这个连接读取资源的内容。资源不仅仅指的是网络资源,还可以是本地文件、一个jar包等等。1、来个Demo举个例子,比如你想到访问www.baidu.com这个百度首页网络资源,那么此时就可以这么写public
2023年8月1日
其他

1.5万字+30张图盘点索引常见的11个知识点

大家好,我是三友~~今天来盘点一下关于MySQL索引常见的知识点本来这篇文章我前两个星期就打算写了,提纲都列好了,但是后面我去追《漫长的季节》这部剧去了,这就花了一个周末的时间,再加上后面一些其它的事,导致没来得及写不过不要紧,好饭不怕晚,虽迟但到,走起,开干!对了,本文主要是针对InnoDB存储引擎进行讲解。索引分类
2023年5月23日
其他

Sentinel为什么这么强,我扒了扒背后的实现原理

大家好,我是三友~~最近我在整理代码仓库的时候突然发现了被尘封了接近两年之久的Sentinel源码库两年前我出于好奇心扒了一下Sentinel的源码,但是由于Sentinel本身源码并不复杂,在简单扒了扒之后几乎就再没扒过了那么既然现在又让我看到了,所以我准备再来好好地扒一扒,然后顺带写篇文章来总结一下。Sentinel简介
2023年4月24日
其他

扒一扒Nacos、OpenFeign、Ribbon、loadbalancer组件协调工作的原理

大家好,我是三友~~前几天有个大兄弟问了我一个问题,注册中心要集成SpringCloud,想实现SpringCloud的负载均衡,需要实现哪些接口和规范。既然这个兄弟问到我了,而我又刚好知道,这不得好好写一篇文章来回答这个问题,虽然在后面的聊天中我已经回答过了。接下来本文就来探究一下Nacos、OpenFeign、Ribbon、loadbalancer等组件协调工作的原理,知道这些原理之后,就知道应该需要是实现哪些接口了。再多说一句,本文并没有详细地深入剖析各个组件的源码,如果有感兴趣的兄弟可以从公众号后台菜单栏中的文章分类中查看我之前写的关于Nacos、OpenFeign、Ribbon源码剖析的文章。Nacos
2023年4月10日
其他

为什么消息会重复消费,我从RocketMQ源码中扒出了7种原因,有点小坑

大家好,我是三友~~在众多关于MQ的面试八股文中有这么一道题,“如何保证MQ消息消费的幂等性”。为什么需要保证幂等性呢?是因为消息会重复消费。为什么消息会重复消费?明明已经消费了,为什么消息会被再次被消费呢?不同的MQ产生的原因可能不一样本文就以RocketMQ为例,来扒一扒RocketMQ中会导致消息重复消息的原因,最终你会发现,其实消息重复消费算是RocketMQ无奈的“bug”。如果有对RocketMQ不熟悉的小伙伴,可以看看我之前写的
2023年3月20日
其他

从实现到原理,我总结了11种延迟任务的实现方式

大家好,我是三友~~延迟任务在我们日常生活中比较常见,比如订单支付超时取消订单功能,又比如自动确定收货的功能等等。所以本篇文章就来从实现到原理来盘点延迟任务的11种实现方式,这些方式并没有绝对的好坏之分,只是适用场景的不大相同。DelayQueue
2023年2月27日
其他

用Redis实现延迟队列,我研究了两种方案,发现并不简单

}}整个工程目录也简单代码写好,启动应用之后我直接通过Redis命令设置消息,就没通过代码发送消息了,消息的key为sanyou,值为task,值不重要,过期时间为5sset
2023年2月13日
其他

如何去阅读源码,我总结了18条心法

大家好,我是三友~~这篇文章我准备来聊一聊如何去阅读开源项目的源码。在聊如何去阅读源码之前,先来简单说一下为什么要去阅读源码,大致可分为以下几点原因:最直接的原因,就是面试需要,面试喜欢问源码,读完源码才可以跟面试官battle提升自己的编程水平,学习编程思想和和代码技巧熟悉技术实现细节,提高设计能力...那么到底该如何去阅读源码呢?这里我总结了18条心法,助你修炼神功学好JDK
2023年2月6日
其他

扒一扒Bean注入到Spring的那些姿势

大家好,我是三友~~这篇文章我准备来扒一扒Bean注入到Spring的那些姿势。其实关于Bean注入Spring容器的方式网上也有很多相关文章,但是很多文章可能会存在以下常见的问题注入方式总结的不全没有分析可以使用这些注入方式背后的原因没有这些注入方式在源码中的应用示例...所以本文就带着解决上述的问题的目的来重新梳理一下Bean注入到Spring的那些姿势。配置文件
2023年1月30日
其他

RocketMQ消息短暂而又精彩的一生

大家好,我是三友~~这篇文章我准备来聊一聊RocketMQ消息的一生。不知你是否跟我一样,在使用RocketMQ的时候也有很多的疑惑:消息是如何发送的,队列是如何选择的?消息是如何存储的,是如何保证读写的高性能?RocketMQ是如何实现消息的快速查找的?RocketMQ是如何实现高可用的?消息是在什么时候会被清除?...本文就通过探讨上述问题来探秘消息在RocketMQ中短暂而又精彩的一生。如果你还没用过RocketMQ,可以看一下这篇文章RocketMQ保姆级教程核心概念
2023年1月9日
其他

项目中引进这玩意,排查日志又快又准!

Thread的方法来创建异步线程,然后来执行,这种方式TLog是天然支持携带traceId的,如图。执行结果从这可以看出这种异步方式的确成功传递了traceId。1.2
2022年12月15日
其他

两万字盘点那些被玩烂了的设计模式

大家好,我是三友~~之前有小伙伴私信我说看源码的时候感觉源码很难,不知道该怎么看,其实这有部分原因是因为没有弄懂一些源码实现的套路,也就是设计模式,所以本文我就总结了9种在源码中非常常见的设计模式,并列举了很多源码的实现例子,希望对你看源码和日常工作中有所帮助。单例模式
2022年11月15日
其他

写出漂亮代码的45个小技巧

bytes);}如果选择了阿里云OSS作为存储服务器,那么就可以基于OSS实现一个FileStorage,在项目中哪里需要存储的时候,只要实现注入这个接口就可以了。@Autowiredprivate
2022年10月20日
其他

撸了一个简易的配置中心,顺带还给整合到了SpringCloud

对象里面。3.2配置刷新源码流程这个图新增了对于加了@ConfigurationProperties数据绑定的对象原理的分析。整合SpringCloud和测试
2022年10月13日
其他

7000字+24张图带你彻底弄懂线程池

大家好,我是三友~~今天跟大家聊一聊无论是在工作中常用还是在面试中常问的线程池,通过画图的方式来彻底弄懂线程池的工作原理,以及在实际项目中该如何自定义适合业务的线程池。一、什么是线程池
2022年9月24日
其他

RocketMQ保姆级教程

-Xmn512m修改Broker配置文件broker.conf这里需要改一下Broker配置文件,需要指定NameServer的地址,因为需要Broker需要往NameServer注册vi
2022年8月15日
其他

RocketMQ的push消费方式实现的太聪明了

大家好,我是三友,我又来了~~最近仍然畅游在RocketMQ的源码中,这几天刚好翻到了消费者的源码,发现RocketMQ的对于push消费方式的实现简直太聪明了,所以趁着我脑子里还有点印象的时候,赶紧来写一篇文章,来掰扯一下,防止过两天就忘得一干二净了。MQ消费方式
2022年8月8日
其他

三万字盘点Spring/Boot的那些常用扩展点

大家好,我是三友。Spring对于每个Java后端程序员来说肯定不陌生,日常开发和面试必备的。本文就来盘点Spring/SpringBoot常见的扩展点,同时也来看看常见的开源框架是如何基于这些扩展点跟Spring/SpringBoot整合的。话不多说,直接进入正题。FactoryBean
2022年7月25日
其他

@Async注解的坑,小心

if,也就不会抛出异常,所以可以通过将allowRawInjectionDespiteWrapping设置成true来解决报错的问题,代码如下:@Componentpublic
2022年7月11日
其他

一网打尽异步神器CompletableFuture

大家好,我是三友。最近一直畅游在RocketMQ的源码中,发现在RocketMQ中很多地方都使用到了CompletableFuture,所以今天就跟大家来聊一聊JDK1.8提供的异步神器CompletableFuture,并且最后会结合RocketMQ源码分析一下CompletableFuture的使用。Future接口以及它的局限性
2022年7月4日
其他

Zookeeper分布式锁实现Curator十一问

服务端的会话失效(例如断开连接),那么节点就会被删除。2)持久化节点持久化节点指的是节点创建后,即使创建节点的客户端和
2022年6月12日
其他

Redis分布式锁实现Redisson 15问

大家好,我是三友。在一个分布式系统中,由于涉及到多个实例同时对同一个资源加锁的问题,像传统的synchronized、ReentrantLock等单进程情况加锁的api就不再适用,需要使用分布式锁来保证多服务实例之间加锁的安全性。常见的分布式锁的实现方式有zookeeper和redis等。而由于redis分布式锁相对于比较简单,在实际的项目中,redis分布式锁被用于很多实际的业务场景中。redis分布式锁的实现中又以Redisson比较出名,所以本文来着重看一下Redisson是如何实现分布式锁的,以及Redisson提供了哪些其它的功能。一、如何保证加锁的原子性说到redis的分布式锁,可能第一时间就想到了setNx命令,这个命令保证一个key同时只能有一个线程设置成功,这样就能实现加锁的互斥性。但是Redisson并没有通过setNx命令来实现加锁,而是自己实现了一套完成的加锁的逻辑。Redisson的加锁使用代码如下,接下来会有几节着重分析一下这段代码逻辑背后实现的原理。先通过RedissonClient,传入锁的名称,拿到一个RLock,然后通过RLock实现加锁和释放锁。getLock获得的RLock接口的实现是RedissonLock,所以我们看一下RedissonLock对lock()方法的实现。lock方法会调用重载的lock方法,传入的leaseTime为-1,调用到这个lock方法,之后会调用tryAcquire实现加锁的逻辑。tryAcquire最后会调到tryAcquireAsync方法,传入了leaseTime和当前加锁线程的id。tryAcquire和tryAcquireAsync的区别就是tryAcquireAsync是异步执行,而tryAcquire是同步等待tryAcquireAsync的结果,也就是异步转同步的过程。tryAcquireAsync方法会根据leaseTime是不是-1来判断使用哪个分支加锁,其实不论走哪个分支,最后都是调用tryLockInnerAsync方法来实现加锁,只不过是参数不同罢了。但是我们这里的leaseTime其实就是-1,所以会走下面的分支,尽管传入到tryAcquireAsync的leaseTime是-1,但是在调用tryLockInnerAsync方法传入的leaseTime参数是internalLockLeaseTime,默认是30s。tryLockInnerAsync方法。通过tryLockInnerAsync方法的实现可以看出,最终加锁是通过一段lua脚本来实现加锁的,redis在执行lua脚本的时候是可以保证加锁的原子性的,所以Redisson实现加锁的原子性是依赖lua脚本来实现的。其实对于RedissonLock这个实现来说,最终实现加锁的逻辑都是通过tryLockInnerAsync来实现的。来一张图总结一下lock方法加锁的调用逻辑。二、如何通过lua脚本实现加锁通过上面分析可以看出,redis是通过执行lua脚本来实现加锁,保证加锁的原子性。那么接下来分析一下这段lua脚本干了什么。其中这段脚本中的lua脚本中的参数的意思:KEYS[1]:就是锁的名称,对于我们的demo来说,就是myLockARGV[1]:就是锁的过期时间,不指定的话默认是30sARGV[2]:代表了加锁的唯一标识,由UUID和线程id组成。一个Redisson客户端一个UUID,UUID代表了一个唯一的客户端。所以由UUID和线程id组成了加锁的唯一标识,可以理解为某个客户端的某个线程加锁。那么这些参数是怎么传过去的呢,其实是在这里。getName:方法就是获取锁的名称leaseTime:就是传入的锁的过期时间,如果指定超时时间就是指定的时间,没指定默认是30sgetLockName:就是获取加锁的客户端线程的唯一标识。分析一下这段lua的加锁的逻辑。1)先调用redis的exists命令判断加锁的key存不存在,如果不存在的话,那么就进入if。不存在的意思就是还没有某个客户端的某个线程来加锁,第一次加锁肯定没有人来加锁,于是第一次if条件成立。2)然后调用redis的hincrby的命令,设置加锁的key和加锁的某个客户端的某个线程,加锁次数设置为1,加锁次数很关键,是实现可重入锁特性的一个关键数据。用hash数据结构保存。hincrby命令完成后就形成如下的数据结构。myLock:{"b983c153-7421-469a-addb-44fb92259a1b:1":1}3)最后调用redis的pexpire的命令,将加锁的key过期时间设置为30s。从这里可以看出,第一次有某个客户端的某个线程来加锁的逻辑还是挺简单的,就是判断有没有人加过锁,没有的话就自己去加锁,设置加锁的key,再存一下加锁的线程和加锁次数,设置一下锁的过期时间为30s。画一张图来看一下lua脚本加锁的逻辑干了什么。至于第二段if是干什么的,我们后面再说。三、为什么需要设置加锁key的过期时间通过上面的加锁逻辑可以知道,虽然我们没有手动设置锁的过期时间,但是Redisson默认会设置一个30s的过期时间,为什么需要过期时间呢?主要原因是为了防止死锁。当某个客户端获取到锁,还没来得及主动释放锁,那么此时假如客户端宕机了,又或者是释放锁失败了,那么如果没有设置过期时间,那么这个锁key会一直在,那么其它线程来加锁的时候会发现key已经被加锁了,那么其它线程一直会加锁失败,就会产生死锁的问题。四、如何自动延长加锁时间通过上面的分析我们都知道,在加锁的时候,就算没有指定锁的过期时间,Redisson默认也会给锁设置30s的过期时间,主要是用来防止死锁。虽然设置了默认过期时间能够防止死锁,但是这也有一个问题,如果在30s内,任务没有结束,但是锁已经被释放了,失效了,一旦有其它线程加锁成功,那么就完全有可能出现线程安全数据错乱的问题。所以Redisson对于这种未指定超时时间的加锁,就实现了一个叫watchdog机制,也就是看门狗机制来自动延长加锁的时间。在客户端通过tryLockInnerAsync方法加锁成功之后,如果你没有指定锁过期的时间,那么客户端会起一个定时任务,来定时延长加锁时间,默认每10s执行一次。所以watchdog的本质其实就是一个定时任务。最后会定期执行如下的一段lua脚本来实现加锁时间的延长。解释一下这段lua脚本中参数的意思,其实是跟加锁的参数的意思是一样KEYS[1]:就是锁的名称,对于我们的demo来说,就是myLockARGV[1]:就是锁的过期时间ARGV[2]:代表了加锁的唯一标识,b983c153-7421-469a-addb-44fb92259a1b:1。这段lua脚本的意思就是判断来续约的线程跟加锁的线程是同一个,如果是同一个,那么将锁的过期时间延长到30s,然后返回1,代表续约成功,不是的话就返回0,代表续约失败,下一次定时任务也就不会执行了。注意:因为有了看门狗机制,所以说如果你没有设置过期时间(超时自动释放锁的逻辑后面会说)并且没有主动去释放锁,那么这个锁就永远不会被释放,因为定时任务会不断的去延长锁的过期时间,造成死锁的问题。但是如果发生宕机了,是不会造成死锁的,因为宕机了,服务都没了,那么看门狗的这个定时任务就没了,也自然不会去续约,等锁自动过期了也就自动释放锁了,跟上述说的为什么需要设置过期时间是一样的。五、如何实现可重入加锁可重入加锁的意思就是同一个客户端同一个线程也能多次对同一个锁进行加锁。也就是同时可以执行多次
2022年5月29日
其他

有关循环依赖和三级缓存的这些问题,你都会么?(面试常问)

大家好。我们都知道,Spring可以通过三级缓存解决循环依赖的问题,这也是面试中很常见的一个面试题,本文就来着重讨论一下有关循环依赖和三级缓存的问题。一、什么是循环依赖大家平时在写业务的时候应该写过这样的代码。其实这种类型就是循环依赖,就是AService
2022年5月22日
其他

万字+28张图带你探秘小而美的规则引擎框架LiteFlow

大家好,今天给大家介绍一款轻量、快速、稳定可编排的组件式规则引擎框架LiteFlow。一、LiteFlow的介绍LiteFlow官方网站和代码仓库地址官方网站:https://yomahub.com/liteflowGitee托管仓库:https://gitee.com/dromara/liteFlowGithub托管仓库:https://github.com/dromara/liteflow前言在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。时间一长,项目几经易手,维护的成本就会越来越高。各种硬代码判断,分支条件越来越多。代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更业务流程,几乎很难实现。LiteFlow框架的作用LiteFlow就是为解耦复杂逻辑而生,如果你要对复杂业务逻辑进行新写或者重构,用LiteFlow最合适不过。它是一个轻量,快速的组件式流程引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件,并支持热加载规则配置,实现即时修改。使用LiteFlow,你需要去把复杂的业务逻辑按代码片段拆分成一个个小组件,并定义一个规则流程配置。这样,所有的组件,就能按照你的规则配置去进行复杂的流转。LiteFlow的设计原则LiteFlow是基于工作台模式进行设计的,何谓工作台模式?n个工人按照一定顺序围着一张工作台,按顺序各自生产零件,生产的零件最终能组装成一个机器,每个工人只需要完成自己手中零件的生产,而无需知道其他工人生产的内容。每一个工人生产所需要的资源都从工作台上拿取,如果工作台上有生产所必须的资源,则就进行生产,若是没有,就等到有这个资源。每个工人所做好的零件,也都放在工作台上。这个模式有几个好处:每个工人无需和其他工人进行沟通。工人只需要关心自己的工作内容和工作台上的资源。这样就做到了每个工人之间的解耦和无差异性。即便是工人之间调换位置,工人的工作内容和关心的资源没有任何变化。这样就保证了每个工人的稳定性。如果是指派某个工人去其他的工作台,工人的工作内容和需要的资源依旧没有任何变化,这样就做到了工人的可复用性。因为每个工人不需要和其他工人沟通,所以可以在生产任务进行时进行实时工位更改:替换,插入,撤掉一些工人,这样生产任务也能实时地被更改。这样就保证了整个生产任务的灵活性。这个模式映射到LiteFlow框架里,工人就是组件,工人坐的顺序就是流程配置,工作台就是上下文,资源就是参数,最终组装的这个机器就是这个业务。正因为有这些特性,所以LiteFlow能做到统一解耦的组件和灵活的装配。二、LiteFlow的使用1)非Spring环境下引入pom依赖
2022年5月15日
其他

自从装了这款插件,再也不怕沉迷撸码了

大家好,我是三友,今天不卷技术,来给大家分享一款防沉迷撸码的插件。一、前言身为一个热爱撸码的社会良好青年,不知道大家有没有跟我一样,一旦开始撸码,总会忘记时间,无意间就会导致长时间久坐,并且不会去主动去喝水,总是等口渴了才会去喝水。长此以往,可能会导致出现腰酸背痛等身体上的一些小毛病。我以前也尝试通过手环或者手表来提醒自己去改变这种状态,但是效果不明显,很容易忽略手环或者手表的提醒。于是,我找到了一款名叫StopCoding的防沉迷撸码的IDEA插件,这款插件可以在撸了一定时间码之后强制休息一定的时间,自己用了一段时间觉得很不错,所以决定推荐给大家。二、安装StopCoding安装StopCoding其实很简单,在IDEA的插件市场中就有这款软件。1)
2022年5月12日
其他

7000字+24张图带你彻底弄懂线程池

大家好,我是三友。今天跟大家聊一聊无论是在工作中常用还是在面试中常问的线程池,通过画图的方式来彻底弄懂线程池的工作原理,以及在实际项目中该如何自定义适合业务的线程池。一、什么是线程池线程池其实是一种池化的技术的实现,池化技术的核心思想其实就是实现资源的一个复用,避免资源的重复创建和销毁带来的性能开销。在线程池中,线程池可以管理一堆线程,让线程执行完任务之后不会进行销毁,而是继续去处理其它线程已经提交的任务。使用线程池的好处降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统
2022年5月3日
其他

【SpringCloud原理】OpenFeign原来是这么基于Ribbon来实现负载均衡的

大家好,前面我已经剖析了OpenFeign的动态代理生成原理和Ribbon的运行原理,这篇文章来继续剖析SpringCloud组件原理,来看一看OpenFeign是如何基于Ribbon来实现负载均衡的,两组件是如何协同工作的。一、Feign动态代理调用实现rpc流程分析通过Feign客户端接口的动态代理生成原理讲解,我们可以清楚的知道,Feign客户端接口的动态代理生成是基于JDK的动态代理来实现的,那么在所有的方法调用的时候最终都会走InvocationHandler接口的实现,默认就是ReflectiveFeign.FeignInvocationHandler,那我们接下来就来看看,FeignInvocationHandler是如何实现rpc调用的。FeignInvocationHandler对于invoke方法的实现。
2022年4月30日
其他

【SpringCloud原理】Ribbon核心组件以及运行原理源码剖析

大家好,本文我将继续来剖析SpringCloud中负载均衡组件Ribbon的源码。本来我是打算接着OpenFeign动态代理生成文章直接讲Feign是如何整合Ribbon的,但是文章写了一半发现,如果不把Ribbon好好讲清楚,那么有些Ribbon的细节理解起来就很困难,所以我还是打算单独写一篇文章来剖析Ribbon的源码,这样在讲Feign整合Ribbon的时候,我就不再赘述这些细节了。好了,话不多说,直接进入主题。一、Ribbon的核心组件1、Server这是个很简单的东西,就是服务实例数据的封装,里面封装了服务实例的ip和端口之类的,一个服务有很多台机器,那就有很多个Server对象。2、ServerListpublic
2022年4月27日
其他

【SpringCloud原理】OpenFeign之FeignClient动态代理生成原理

看Spring源码不得不会的@Enable模块驱动实现原理讲解,这里详细讲解了@Import注解的作用。接下来看一下registerBeanDefinitions的实现@Overridepublic
2022年4月23日
其他

线程池面试连环炮,你能抗住几题?

大家好,最近有朋友在面试时,刚好被问到了线程池相关的问题,于是我想就抽时间整理了一些关于线程池的面试题来分享给大家。1.为什么要用线程池,线程池有什么好处么?线程池,简单的来说就是管理了一堆线程的地方,这里的线程在执行完任务之后不是进行销毁,而是进行阻塞等待继续获取任务,从而实现了线程的重复利用,降低了线程的创建和销毁的资源消耗。2.线程池有哪些参数?corePoolSize:线程池中用来工作的核心的线程数量。maximumPoolSize:最大线程数,线程池允许创建的最大线程数。keepAliveTime:超出
2022年4月21日
其他

某小厂面试题:什么是虚假唤醒?

大家好,今天来跟大家聊聊某小厂的一道面试题,什么是虚假唤醒。生产者消费者模型引出虚假唤醒的问题说虚假唤醒之前,我们来测试一段经典的生产者和消费者代码。public
2022年4月20日
其他

为什么有了并发安全的集合还需要读写锁?

大家好,我是三友,这篇文章想来跟大家来探讨一下,在Java中已经提供了并发安全的集合,为什么有的场景还需要使用读写锁,直接用并发安全的集合难道不行么?在java中,并发安全的集合有很多,这里我就选用常见的CopyOnWriteArrayList为例,来说明一下读写锁的价值到底提现在哪。CopyOnWriteArrayList核心源码分析接下来我们分析一下CopyOnWriteArrayList核心的增删改查的方法成员变量//独占锁final
2022年4月15日
其他

为什么Java有了synchronized之后还造了Lock锁这个轮子?

众所周知,synchronized和Lock锁是java并发变成中两大利器。但是为什么Java有了synchronized之后还是提供了Lock接口这个api,难道仅仅只是重复造了轮子这么简单么?本文就来探讨一下这个问题。谈到这个问题,其实很多同学第一反应都会说,Lock锁的性能比synchronized好,synchronized属于重量级的锁。但是在JDK
2022年4月13日
其他

synchronized真的很重么?

(粗化)到整个操作序列的外部。以上述代码为例,也就是扩展到把for循环这个操作加锁,这样只需要加锁一次就可以了。总结所以,通过本篇文章可以看出,jdk对synchronized
2022年4月10日
其他

一文带你看懂Java中的Lock锁底层AQS到底是如何实现的

欢迎点击关注公众号,利用碎片化时间学习,每天进步一点点。相信大家对Java中的Lock锁应该不会陌生,比如ReentrantLock,锁主要是用来解决解决多线程运行访问共享资源时的线程安全问题。那你是不是很好奇,这些Lock锁api是如何实现的呢?本文就是来探讨一下这些Lock锁底层的AQS(AbstractQueuedSynchronizer)到底是如何实现的。本文是基于ReentrantLock来讲解,ReentrantLock加锁只是对AQS的api的调用,底层的锁的状态(state)和其他线程等待(Node双向链表)的过程其实是由AQS来维护的加锁我们先来看看加锁的过程,先看源码,然后模拟两个线程来加锁的过程。上图是ReentrantLock的部分实现。里面有一个Sync的内部类的实例变量,这个Sync内部类继承自AQS,Sync子类就包括公平锁和非公平锁的实现。说白了其实ReentrantLock是通过Sync的子类来实现加锁。我们就来看一下Sync的非公平锁的实现NonfairSync。重写了它的lock加锁方法,在实现中因为是非公平的,所以一进来会先通过cas尝试将AQS类的state参数改为1,直接尝试加锁。如果尝试加锁失败会调用AQS的acquire方法继续尝试加锁。假设这里有个线程1先来调用lock方法,那么此时没有人加锁,那么就通过CAS操作,将AQS中的state中的变量由0改为1,代表有人来加锁,然后将加锁的线程设置为自己如图。那么此时有另一个线程2来加锁,发现通过CAS操作会失败,因为state已经被设置为1了,线程线程2就会设置失败,那么此时就会走else,调用AQS的acquire方法继续尝试加锁。进入到acquire会先调用tryAcquire再次尝试加锁,而这个tryAcquire方法AQS其实是没有什么实现的,会调用到NonfairSync里面的tryAcquire,而tryAcquire实际会调用到Sync内部类里面的nonfairTryAcquire非公平尝试加锁方法。先获取锁的状态,判断锁的状态是不是等于0,等于0说明没人加锁,可以尝试去加,如果被加锁了,就会走else
2022年3月28日
其他

Java 锁机制了解一下

在多线程环境下,程序往往会出现一些线程安全问题,为此,Java提供了一些线程的同步机制来解决安全问题,比如:synchronized锁和Lock锁都能解决线程安全问题。悲观锁和乐观锁我们可以将锁大体分为两类:悲观锁乐观锁顾名思义,悲观锁总是假设最坏的情况,每次获取数据的时候都认为别的线程会修改,所以每次在拿数据的时候都会上锁,这样其它线程想要修改这个数据的时候都会被阻塞直到获取锁。比如MySQL数据库中的表锁、行锁、读锁、写锁等,Java中的synchronized和ReentrantLock等。而乐观锁总是假设最好的情况,每次获取数据的时候都认为别的线程不会修改,所以并不会上锁,但是在修改数据的时候需要判断一下在此期间有没有别的线程修改过数据,如果没有修改过则正常修改,如果修改过则这次修改就是失败的。常见的乐观锁有版本号控制、CAS算法等。悲观锁应用案例如下:public
2022年3月23日
其他

面试必须要知道的MySQL知识--索引

xx1,xx2,xx3基于xx1,xx2,xx3建立联合索引这种情况下,你仅仅需要联合索引里的几个字段的值,那么其实就只要扫描联合索引的索引树就可以了,不需要回表去聚簇索引里找其他字段了。10.7
2022年3月8日
其他

面试必须要知道的MySQL知识--三大日志和事务

概念如果一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来,那就意味着发生了幻读。9.3.2
2022年3月5日
其他

面试必须要知道的MySQL知识(上)

欢迎点击关注公众号,利用碎片化时间学习,每天进步一点点。来源:https://blog.csdn.net/a18602320276/article/details/122917218本文跟你来聊聊MySQL一些底层原理知识,由于文章内容较多,所以拆分为好几篇文章,欢迎大家关注公众号,及时获得下文。1
2022年3月3日
其他

看Spring源码不得不会的@Enable模块驱动实现原理讲解

垃圾回收过程的异同正确理解MySQL的MVCC及实现原理画图带你理清TCP协议三次握手和四次挥手面试官:请说一说java中的AQSMybatis
2022年2月27日
其他

面试官:JDK1.8 HashMap扩容rehash算法是如何优化的?

本文跟大家聊一聊一个常见的面试题,那就是JDK1.8
2022年2月26日
其他

CMS 和 G1 垃圾回收过程的异同

欢迎点击关注公众号,利用碎片化时间学习,每天进步一点点。来源:https://blog.csdn.net/SnailMann/article/details/122898669垃圾回收CMS
2022年2月22日
其他

面试被问到Redis的持久化策略别再不会啦

欢迎点击关注公众号,学习更多进阶技术。https://blog.csdn.net/SnailMann/article/details/97787049前提概念持久化的作用Redis持久化的方式RDB持久化策略什么是RDB?RDB的两种策略方式如何使用RDB策略备份数据?RDB的原理是什么?AOF持久化策略什么是AOFAOF的原理是什么AOF的三种策略AOF的重写机制RDB和AOF的抉择RDB还是AOF?Redis4.0的混合持久化运维最佳实践其他问题RDB持久化操作时,子进程拷贝父进程的数据副本用于持久化,不会增加内存消耗吗?为什么Redis的AOF机制是先成功命令才再记录日志?AOF文件过大会怎么办?前提概念持久化的作用什么是持久化?我们将能把内存中的数据保存到磁盘中存储的行为就称之为持久化为什么需要持久化?Redis所有的数据保存在内存中,如何Redis实例突然的宕机,其占用的全部内存就会被系统释放,导致Redis的数据全部丢失,因此必须要有一种机制来保证Redis的数据不会因为故障而丢失。这一机制就是Redis的持久化机制。所以持久化操作的作用就是把Redis中的数据,保存到磁盘中。避免因为实例宕机,而出现数据丢失的现象。Redis持久化的方式Redis为我们提供了主要的两种持久化方式数据快照
2022年2月19日
其他

正确理解MySQL的MVCC及实现原理

欢迎点击关注公众号,学习更多进阶技术。来源:https://blog.csdn.net/SnailMann/article/details/94724197!首先声明,MySQL
2022年2月13日
其他

继续画图带你学习TCP 其他 7 大特性

个字节都行举例:双方建立连接,需要在连接后一段时间内发送不同结构数据,如连接后,有好几种结构“你好不好”“好个P”读多少个字节才是一个完整的应用层数据包,这个是不清楚的若一次读一个汉字,读出来就是
2022年2月11日
其他

面试常问的dubbo的spi机制到底是什么?(下)

接口讲解ExtensionInjector就是注入器,通过这个可以获取到被依赖注入的对象,这是个接口,有很多实现,这里是
2022年2月8日