- 博客(172)
- 收藏
- 关注
原创 Java 数据库连接池
性能不如 HikariCP,但是功能更丰富,支持 sql 级别的监控,慢查询监控,连接池状态的监控等。HikariCP 包含了许多微观的优化,这些优化单独来看几乎无法衡量,但结合起来就能提升整体性能。经过阿里实践过的,经受住了双十一的考验,有大厂做背书,用着放心。● 代码级别的优化-利用无锁的 ConcurrentBag。甚至在数百万次的调用中,优化的级别是以毫秒的时间来衡量的。● 字节码级别的优化-利用更容易被 JVM 优化的指令。● 字节码级别的优化-尽量的利用 JIT 的内联手段。
2025-03-30 17:51:24
358
原创 B站播放数量如何实现,高并发读写计数难点
再具体一点说,读压力,读取视频的播放量,可以直接从 Redis 缓存中读取,甚至可以考虑给 kv 不设置过期时间,这样这不会有缓存击穿、穿透的问题了。写压力,更新视频的播放量,使用异步 + 批量合并的思想,先将大量的更新写请求在本地内存中合并起来,然后在周期性的去写库,大大降低了数据库的压力。关于数据的实时性,就看定时任务的周期、产品提的需求、视频的热度、节点的可靠性。这样实现,最大的好处就是简单,但是我们马上就能发现一个非常严重的问题,按照大厂的规模,高并发的场景,这个计数服务肯定是要集群部署的。
2024-06-06 21:06:02
416
原创 压测短链接项目的时候,由 Jmeter 报错:java.net.BindException:Address already in use,所引发的一系列困惑与思考
2024.1.31 压测短链接项目的时候,由 Jmeter 的一个报错,所引发的一系列困惑与思考
2024-01-31 13:42:26
748
原创 你知道有哪些常用的限流算法吗,分别有什么优缺点呢?
计数器 / 固定窗口算法a. 实现很简单,通过 Redis 的 inc 自增命令就可以实现了b. 存在“毛刺现象”,如我们一分钟内限流100次,在持续性大流量下,很有可能出现这种情况,第一秒钟解收了100个请求,后面59秒都是拒绝状态,61秒又接收了100个请求,后面59持续拒绝。。。也就是该算法无法均匀的限制流量c. 在两个时间窗口的临界点,存在《临界问题》滑动窗口算法a. 将原本的粗粒度细化,如将1分钟限制100请求切分成6个10秒钟的小窗口b. 可以很大程度的解决固定窗口的《临界问题》
2023-12-07 10:36:10
206
原创 谈谈对于 HashSet 的理解
只不过 HashSet 的所有 value 都是由一个变量 Present 来填充的,是一个 Object 对象。其实内部就是依靠 HashMap 实现的,HashSet 使用了组合,有一个成员变量就是 HashMap。add 方法啊,remove 方法啊,底层都是调用的 HashMap 中的方法。
2023-10-28 13:53:53
165
原创 如何解决 HashMap 线程不安全的问题呢?
● Collections.synchronizedMap 是使用 Collections 集合工具的内部类,通过传入 Map 封装出一个 SynchronizedMap 对象,内部定义了一个对象锁,方法内通过对象锁实现;● ConcurrentHashMap 在 jdk1.7 中使用分段锁,在 jdk1.8 中使用 CAS+synchronized。● HashTable 是直接在操作方法上加 synchronized 关键字,锁住整个table数组,粒度比较大;
2023-10-28 11:43:04
160
原创 Hashmap 扩容流程?
会遍历每个哈希桶,如果只有一个节点的话,就直接插入到 e.hash & (newCap - 1) 的位置;如果是链表,将原来的链表拆分成两个链表, lo 链表和 hi 链表,并将这两个链表分别放到新的table的 j 位置和 j + oldCap 上, j 位置就是原链表在原 table 中的位置, 拆分的标准就是:如果 (e.hash & oldCap) == 0,就放到原本的位置上。Hashmap 扩容流程?
2023-10-24 21:29:59
655
原创 解决 hash 冲突的办法有哪些?HashMap 用的哪种?
解决Hash冲突方法有:开放定址法、再哈希法、链地址法(拉链法)、建立公共溢出区。HashMap中采用的是。解决 hash 冲突的办法有哪些?HashMap 用的哪种?
2023-10-24 21:27:59
437
原创 HashMap 的底层数据结构是什么?
在JDK1.8 中,由“数组+链表+红黑树”组成:当链表过长,则会严重影响 HashMap 的性能,红黑树搜索时间复杂度是 O(logn),而链表是糟糕的 O(n)。在JDK1.7 中,由“数组+链表”组成:数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。● 当链表长度 > 8 && 数组长度 >= 64 才会转红黑树;其实这种情况,发生的概率很低。● 将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择。,而不是转换为红黑树,以减少搜索时间。
2023-10-24 21:27:06
365
原创 对于 HashMap 自己的理解
putVal(),getNode()方法,都是一上来就判断,头节点是不是我们要找的节点,比较 hash,key。因为哈希冲突,毕竟是发生概率很小的事情,大概率头节点就是我们要找的节点。至于后面,走红黑树的判断逻辑,去遍历链表,都是小概率事件了。通常我们的 Map 里面是不会存储这么多的数据的,所以通常情况下,并不会发生从链表向红黑树的转换。把 key 为 null 的 Node 节点放在了索引下标为 0 的地方。默认的数组容量为 16,默认的加载因子为 0.75 f。
2023-10-24 21:26:04
101
原创 谈谈 ArrayList
快速失败,modCount 用来记录 ArrayList 结构发生变化的次数,结构发生变化是指添加或者删除至少一个元素的操作,或者是调整内部数组的大小,仅仅只是设置元素的值不算结构发生变化。出于效率的考虑,数组可能长度100,但实际只用了50,剩下的50其实不用序列化,这样可以提高序列化和反序列化的效率,还可以节省内存空间。Arrays 工具类,内部有二分搜索,优化版本的快速排序,双轴快速排序,数组拷贝 copyof,数组填充 fill 等方法。
2023-10-24 21:21:49
155
原创 为什么实际开发中不推荐使用外键?
一般数据库都不会启用读锁,例如MYSQL事务级别设置为读提交,个人认为没有理由使用其它事务级别。数据库的瓶颈在IO,不使用外键代码里做数据完整性检查,磁盘IO省不了,网络IO占用增加。,无论是否使用外键,只要要做数据完整性检查,磁盘IO是省不了的。读写分离也是很成熟的方案。数据库水平扩展不易?64核cpu已发布,最大支持4T内存,主流数据库均支持外键约束。为什么实际开发中不推荐使用外键?只有一个场景不能使用外键,就是。,其它描述都不是真正原因。
2023-10-21 22:31:35
513
2
原创 双重检测锁中的单例对象,为什么要使用 Volatile 修饰?
在还没有执行完第三步之前,又来了一个线程,这时候 instance!= null,于是就拿到了一个没有初始化的空对象,就出现了问题。● 第三步:将instance 指向对象的内存地址,将内存地址赋值给instance。如果第二步和第三步,发生了指令重排序,先执行第三步,再执行第二步。双重检测锁中的单例对象,为什么要使用 Volatile 修饰?保证 instance 变量的可见性,同时可以禁止指令重排序。new 一个对象,在JVM层面是 3 条指令。● 第二步:对对象进行初始化操作。
2023-10-20 17:42:46
189
原创 Volatile 是怎么保证可见性的?谈谈Volatile的可见性
谈到Volatile的可见性,就得先谈谈 Java内存模型。每个线程都有自己的工作内存,数据都是先从主存中,拉取到工作内存中,操作完数据之后,再把数据推送回主存中的。被Volatile修饰的变量,被修改之后,会立刻通过总线,将最新值推送回主存中,还会通过总线通知其他线程,你们工作内存中的数据失效了,要到主存中去拉取最新值。底层原理:对于Volatile 修饰的变量,在汇编层面,会在写操作的前面,加上 lock 指令。● 2.由于总线的嗅探技术,对于lock前缀的嗅探,会导致其他cpu核心的缓存失效。
2023-10-20 17:41:48
185
原创 Volatile 可以保证什么特性?有什么作用?
cpu 都是把数据从内存拉取到自己的缓存中进行运算,然后在写回内存的。每个cpu 核心都有自己独立的缓存。所以就造成了,多核并发的场景下,数据可能被 A 线程修改了,但是其他线程不知道,cpu 核心还在使用缓存中旧的数据。可以保证可见性,有序性,禁止指令重排序。但是不能保证原子性。线程上下文切换的时候,还是有可能出现线程安全问题。Volatile 就是来解决这个缓存一致性问题的。Volatile 可以保证什么特性?有序性,就是所谓的禁止指令重排序。
2023-10-20 17:41:16
184
原创 CAS 产生的 ABA 问题是什么?怎么解决?
CAS操作可能会出现ABA问题,所谓ABA问题是指在执行CAS操作时,由于CAS操作只对值进行比较,不考虑值的版本等其它附加信息,因此可能导致某个线程误认为成功地将值从A修改为B,但实际上另一个线程已经将值从B又修改回了A,这样就会导致该线程认为修改成功,但实际上数据已经被修改了两次,出现了不一致的情况。CAS 产生的 ABA 问题是什么?
2023-10-20 17:40:45
610
原创 CAS 是什么?
更新值之前,会先判断跟预期值一不一样,如果不一样则不更新,这里会有重试机制;如果跟预期值一样,则更新。这里会产生 ABA问题。CAS 一般结合 Volatile,来一起使用。Volatile,来保证能拿到变量的最新值。CAS 是硬件层面,CPU提供的原子指令。由于该指令在硬件层面实现,因此效率非常高。Compare And Swap,无锁编程。
2023-10-20 17:40:07
96
原创 谈谈悲观锁
像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行重试,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。悲观锁就是比较悲观,认为自己使用数据的时候,一定会有其他线程来修改数据,所以在获取数据的时候,会先加锁,确保数据不会被其他线程修改。乐观锁,悲观锁,并不是特指什么具体的锁,而是一种策略,思想。● Lock 接口的实现类,比如 ReentrantLock。● Synchronized 关键字。
2023-10-19 18:14:38
128
原创 谈谈乐观锁
像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去锁的开销,加大了系统的整个吞吐量。乐观锁,只是在更新数据之前,看一下数据有没有被别的线程修改过,如果没有数据没有被别的线程修改过,也不能说的这么绝对,因为存在ABA的问题,就更新数据;如果数据被别的线程修改过了,就不更新,进行重试。乐观锁就是比较乐观,认为自己在使用数据的时候, 不会有其他线程对其进行修改,所以就不会加锁,说白了乐观锁,根本没有锁,是一种无锁编程。乐观锁,悲观锁,并不是特指什么具体的锁,而是一种策略,思想。
2023-10-19 18:14:04
137
原创 Java 对象是什么样子的?
是因为,Java 对象头中存储了 Class 对象的指针。Java 这样设计的好处,可以节省内存的占用,类的元信息有一份就行了,new 出来的对象,可以复用这一份。其实不然,Java 对象中其实只存储了数据,并没有存储其他属性信息。● Object Body,具体的属性值,基本数据类型,就存储值;● Mark Word,32位,64位Java虚拟机,分别是 32 位,64 位。这里的 s 变量,就是我们常说的引用,这里是强引用。指向对象中的 Java对象。Java对象的具体组成:对象头 + 对象体。
2023-10-19 18:11:42
206
原创 说说对 JVM 内存模型的理解
【缓存的命中率是很高的】CPU读写的时候,只操作缓存里的数据,计算完了之后,再把数据写回到内存中。● Java内存模型可不是一个物理上的结构,内存条中可没有什么主内存,工作内存什么的。它只是JVM制定出来的一套规范,Java内存模型,就是对CPU,寄存器,三级缓存,内存,做的一个封装,一个抽象。○ 子线程不能直接使用主内存中的数据,需要先拷贝一份到自己的工作内存中。● 现在的CPU都是多核的,那么缓存就有多个,A 缓存里面的数据被修改了,但是其他缓存并不知道,这时候这会出现数据不一致的问题。
2023-10-19 18:07:42
134
原创 谈谈 Redis 为什么高性能?
● 第三个也就是单线程执行,但大家都没理解单线程执行为啥快,那是因为单线程执行的话你就不需要加锁来控制了,我们要知道锁是一个很重很耗费资源的事情,实测我自己写的渐进式缓存 dict,单线程跑,写100w+读100w,单线程跑也只需要1000毫秒出头。● 第二个就是协议简单,所以序列化和反序列化很快(可能算是最简单的协议了,你自己实现一个都很轻松)谈谈 Redis 为什么高性能?● 第一个是内存存储这个不用说了。
2023-10-18 12:08:52
81
原创 谈谈 Redis 如何来实现分布式锁
但是还是存在分布式问题,比如说,一个客户端在Redis主节点上面加了锁,但是由于主从同步的延迟问题,Redis从节点还没有同步到这个锁数据,这时候其他的客户端就可以在这个Redis从节点上面加相同的锁了。但是 RedLock 只是减少出问题的概率,而且性能差,不推荐使用。这玩意儿就是一种理论设计,平时工作用 setnx+补偿就行了。基于 Hash 数据类型 + Lua脚本 可以实现可重入的分布式锁。基于 setnx 可以实现,但是不是可重入的。谈谈 Redis 如何来实现分布式锁。
2023-10-18 12:04:19
946
原创 Redis 除了做缓存,还能做什么?
防重提交:比如说一个后台系统的保存按钮,很可能出现双击啊等操作,这样就在数据库中新增了多条重复的数据。可以使用 Redis 来做一个防重提交的组件,控制一下提交的时间,比如说,多长时间内的提交,我都认为它是重复的提交。分布式锁:就是利用 setnx key value。如果 key 没有值,就可以设置成功;如果 key 有值了,就设置失败。分布式锁,防重提交,幂等,分布式限流,简易版的消息队列,延迟任务,session 共享。Redis 除了做缓存,还能做什么?
2023-10-18 12:01:08
172
原创 谈谈 Redis 分片集群模式
当 Redis 缓存数据量大到一台服务器无法缓存时,就需要使用 Redis 切片集群(Redis Cluster )方案,它将数据分布在不同的服务器上,以此来降低系统对单主节点的依赖,从而提高 Redis 服务的读写性能。● 手动分配: 可以使用 cluster meet 命令手动建立节点间的连接,组成集群,再使用 cluster addslots 命令,指定每个节点上的哈希槽个数。● 需要注意的是,在手动分配哈希槽时,需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作。
2023-10-17 16:21:46
383
原创 谈谈 Redis 哨兵模式
● 可以在master 主节点挂掉后自动选举新的 master 主节点,实现主从节点故障转移。● master 主节点挂了,切换新的 master 节点会造成未来得及主从同步的数据丢失。● 单个 Redis 只能利用 CPU 的单个核心,应对海量数据捉襟见肘。● 大数据高并发,单个 master 节点内存仍存在上限。● 主从全量同步仍然要耗费大量时间。● Redis 分片集群方案。谈谈 Redis 哨兵模式。
2023-10-17 16:20:55
105
原创 谈谈 Redis 主从复制模式
接下来,我在具体介绍每一个阶段都做了什么。第一阶段:建立链接、协商同步执行了 replicaof 命令后,从服务器就会给主服务器发送 psync 命令,表示要进行数据同步。psync 命令包含两个参数,分别是主服务器的 runID 和复制进度 offset。● runID,每个 Redis 服务器在启动时都会自动生产一个随机的 ID 来唯一标识自己。当从服务器和主服务器第一次同步时,因为不知道主服务器的 run ID,所以将其设置为 “?
2023-10-17 16:19:48
737
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人