1、哈希环算法:
通过将数据分配到一个环形的哈希表上来实现数据的分布,根据环上的顺序依次进行分配。
对于数据敏感的服务不能用取余hash来实现,当新增节点时之前按照取余hash放的数据在新增节点之后在相应的节点找不到数据,而哈希环就可以避免这个问题;另外,取余hash还会造成数据分布不均匀的问题(一些节点存储了大量的数据,一些索引节点却存储很少的数据),这会使系统变得不均衡,影响系统的性能,而哈希环可以实现均匀的数据分布,所以哈希环是一种更可靠的分布式存储方法。
原理图:
先求出不同服务器的哈希值,然后映射到一个范围为0 — 2^32-1的数值空间的圆环中,即将首(0)和尾(2^32-1)相接的圆环。
初始圆环:
新增数据后,映射到这个环上,新增的数据会顺时针寻找,找到的第一个服务器节点就是目标要保存的节点
d1,d2存储到Node B
d3, d4, d5存储到Node C
d6, d7, d8存储到Node A
假如Node B宕机了,其他都不会受到印象,只有d1,d2受到影响,放到Node C
如果新增加一台机器Node D在NodeA和NodeC之间,那么d6,d7就会存储到了Node D,影响也比较小。
改良版
如果出现极限情况下:只有两台机器,然后大量的数据都集中在一台机器上,那么一致性会hash将一个物理节点虚拟出N个虚拟节点来用:
Node A可以虚拟出Node A1,Node A2,Node A3
Node B可以虚拟出Node B1,Node B2,Node B3
2、池化思想:
提前准备一些资源,在需要时可以重复使用这些预先准备的资源。
和StringBuffer类似,先申请一份大的空间,再依次放数据,这样可以防止空间频繁的创建。
优点:可以节省实时分配空间的时间成本;减少对空间的使用,降低高并发下的gc频率,提升性能。
比较典型的几种策略:
内存池:预先申请内存,提高申请内存的速度,减少内存碎片;
连接池:预先申请数据库连接,提升申请链接的速度,降低系统开销;
实例池:循环使用对象,减少资源在初始化和释放时昂贵损耗;
线程池:预先申请线程,重复利用珍贵的线程资源,并且任务到到达时无需等待线程的创建立刻执行。
3、ThreadLocal:
变量在线程间隔离而在方法间共享。
ThreadLocal中的变量属于当前线程,其他线程是无法拿到其中的变量的,即当前线程独有的变量。
使用场景:
在处理多方法中线程并发安全的,最常用的方法,就是使用锁,通过锁来控制多个不同线程对临界区的访问。但是,无论是什么样的锁,乐观锁或者悲观锁,都会在并发冲突的时候对性能产生一定的影响。而ThreadLocal就可以解决这个问题,ThreadLocal 通常用于多线程编程中,用于存储用户 ID 或事务 ID 等信息,这些信息可以在整个执行线程中使用,而对其他线程不可见。
ThreadLocal的使用方法:
创建一个ThreadLocal对象:
private ThreadLocal<Integer> threadLocal= new ThreadLocal<>();
设置和获取threadLocal变量的值:
public int setAndGet(){
threadLocal.set(8);
return threadLocal.get();
}
得到的值为8.
由于ThreadLocal里设置的值,只有当前线程自己看得见,这意味着你不可能通过其他线程为它初始化值。为了弥补这一点,ThreadLocal提供了一个withInitial()方法统一初始化所有线程的ThreadLocal的值:
private ThreadLocal<Integer> threadLocal= ThreadLocal.withInitial(() -> 6);
将threadLocal的初始值设置为6,这对全体线程都是可见的。
ThreadLocal实现原理:
每个线程在往ThreadLocal里设置值的时候,都是往自己的ThreadLocalMap里存,即每个线程都有一个属于自己的ThreadLocalMap,ThreadLocalMap内部维护着Entry数组,每个Entry代表一个完整的对象,key是ThreadLocal本身,value是ThreadLocal的泛型值。
读取也是以某个ThreadLocal作为引用,在自己的map里找对应的key,从而实现了线程隔离。
ThreadLocal的内存泄露问题:
由于ThreadLocalMap中的key为ThreadLocal的弱引用,弱引用比较容易被回收。因此,如果ThreadLocal (ThreadLocalMap的Key)被垃圾回收器回收了,但是因为ThreadLocalMap生命周期和Thread是一样的,它这时候如果不被回收,就会出现这种情况:ThreadLocalMap的key没了,value还在,这就会造成内存泄漏问题。
弱引用:只要垃圾回收机制一运行,不管JVM的内存空间是否充足,都会回收该对象占用的内存。
如何解决内存泄漏问题:
使用完ThreadLocal后,及时调用remove()方法释放内存空间。