- Java并发:彻底理解ThreadLocal
- Java并发:Synchronized原理和优化
- Java并发:java线程池详解
- Java并发:Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发:Java中锁的分类
- Java并发:Java中CAS详解
- Java并发:CopyOnWriteArrayList实现原理及源码分析
- Java基础:Java容器之HashMap
- Java基础: hashmap详解
- Java并发:ConcurrentHashMap解读
- Java基础:JAVA Hashmap的死循环及Java8的修复
- Java并发:BlockingQueue解读
- Java并发:AtomicInteger源码分析——基于CAS的乐观锁实现
- Java基础:值传递和引用传递
- Java基础:强引用、软引用、弱引用、虚引用
- Java基础:Java容器之ArrayList
- Java基础:java中HashSet详解
- Java基础:JAVA中BitSet使用详解
- Java基础:Java容器之LinkedList
- Java基础:java线程状态
- Java基础:Java线程基础
- Java基础:攻破JAVA NIO技术壁垒2
- Java基础:攻破JAVA NIO技术壁垒1
- Java基础:Java IO流学习总结
- Java基础:面向接口编程详解
- Java基础:Java对象初始化过程
- Java基础:Java finally语句到底是在return之前还是之后执行?
- Java基础:Java基础:Java的反射机制
- Java基础:int与Integer区别
- Java基础:java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一
- Java基础:Java中重载与重写的区别
- Java基础:Java 内部类和静态内部类的区别
- Java基础:Java 中的 ==, equals 与 hashCode 的区别与联系
- Java基础:Java抽象类与接口的区别
- Java基础:谈谈final、finally、finalize的区别
- spring cloud config将配置存储在数据库中
- Java基础:面向对象六大原则
- Java基础:Java面向对象的特征
- Java基础:volatile 关键字:保证变量的内存可见性,禁止指令重排
- Java基础:指令重排
- Java基础:ReentrantLock
- 通俗易懂: 内存溢出和内存泄露
- SQL处理报表,列转行的问题
- 集合Collection
- 实现分布式锁
- 实现分布式事务
- 反射
- java中的23种设计模式
- jvm垃圾回收算法
- jvm堆内存模型及gc(垃圾回收)原理
- jvm常用的垃圾回收器
- jvm内存溢出OOM及解决方案
- 主从数据库原理
- mysql的搜索引擎和索引
- mysql索引讲解
- mysql数据库隔离级别
- mysql锁机制-记录锁、间隙锁、临键锁
- 类加载器:
- 线程池
- CPU密集型、IO密集型应用如何分配线程池大小
- JDK1.8新特性
- redis数据类型及应用场景
- redis持久化策略、resp协议介绍
- kafka面试题
- kafka如何保证数据不丢失
- java中引用对象作为map的key,要注意的问题
- spring如何解决循环依赖的问题
- 用redis缓存如何解决数据滞后的问题
- 缓存穿透、缓存雪崩、缓存击穿(热点key问题)
- Mybatis的三级缓存
- 数据计算的时空复杂度
- spring启动过程及原理
- Java阻塞队列
# 解决散列表的hash碰撞,总结:
1. 多重哈希:(如布隆过滤器)散列数组存储的是0,1,hash碰撞后无法判断值key是否一致,所以采用多重hash尽量防止碰撞
2. 开放寻址法:散列数组存储的是Entry,当hash碰撞后可以判断Entry中key是否冲突,不冲突则(hash+1)/array.lenth,继续判断直到找到冲突的Entry或空余的槽位。
3. 链地址法:采用哈希数组+链表结构(数组中每位存储的还是Entry,Entry.next指向下个Entry,形成链表)。发生hash碰撞后,通过Entry.next扫描当前链表。Hash函数尽量保证较少的碰撞和较平均的链表分布,能提高其添加和查找的效率。
NESTED和REQUIRED修饰的内部方法都属于外围方法事务,如果外围方法抛出异常,这两种方法的事务都会被回滚。但是REQUIRED是加入外围方法事务,所以和外围事务同属于一个事务,一旦REQUIRED事务抛出异常被回滚,外围方法事务也将被回滚。
而NESTED是外围方法的子事务,有单独的保存点,所以NESTED方法抛出异常被回滚,不会影响到外围方法的事务。
NESTED和REQUIRES_NEW都可以做到内部方法事务回滚而不影响外围方法事务。但是因为NESTED是嵌套事务,所以外围方法回滚之后,作为外围方法事务的子事务也会被回滚。
而REQUIRES_NEW是通过开启新的事务实现的,内部事务和外围事务是两个事务,外围事务回滚不会影响内部事务
# 总结
BloomFilter具有很好的空间和时间效率,被用来检测一个元素是不是集合中的一个成员。如果检测结果为是,该元素不一定在集合中;但如果检测结果为否,该元素一定不在集合中。因此Bloom filter具有100%的召回率。
BloomFilter是一个长度为长度为n的字节数组byte[n],最大长度为int的长度。每位都初始0,现有3个hash函数,可将字符串计算成int。我们将表中某个column全部获取到,通过这3个hash计算出所有整数,并将byte中这些下标对应的值改成1,即这些column已经全部存到BloomFileter中。
现过来一个key=“DJ0023045”,通过3个hash分别得出10,100,1000这3个数字,然后获取byte[10],byte[100],byte[1000]所在的数字。我们就能判断这个key在BloomFilter中是否存在。
但凡有一个结果是0,都说明这个key没在布隆过滤器里存储过。如果全部得到的是1,那说明可能是存储过,存在一定的误判几率。
因为有可能获取到的这3个数,分别是其他3个key存储在布隆过滤器的,恰巧被该key全部命中。由于hash函数输出的是int类型(最大长度2147483647),存在一定几率的hash碰撞。
# 静态代理总结
1. 静态代理要求目标类和代理类都要实现同一接口
2. 静态代理只代理到方法级别
3. 代码量大,目标类有改动,代理类也要调整
# 动态代理总结
1. JDK代理还是会要求目标类实现一个接口,如果没实现接口无法代理
2. 动态代理是代理到类级别,代码量小
# 应用场景
Spring的事务管理器通过AOP切入业务代码,在进入业务代码前,会依据相应的事务管理器提取出相应的事务对象,假如事务管理器是DataSourceTransactionManager,就会从DataSource中获取一个连接对象,通过一定的包装后将其保存在ThreadLocal中。
而且Spring也将DataSource进行了包装,重写了当中的getConnection()方法,或者说该方法返回的连接将由Spring来控制,这样Spring就能让线程内多次获取到的Connection对象是同一个。为什么要放在ThreadLocal里面呢?由于Spring在AOP后并不能向应用程序传递參数。
应用程序的每一个业务代码是事先定义好的,Spring并不会要求在业务代码的入口參数中必须编写Connection的入口參数。此时Spring选择了ThreadLocal,通过它保证连接对象始终在线程内部,不论什么时候都能拿到,此时Spring很清楚什么时候回收这个连接,也就是很清楚什么时候从ThreadLocal中删除这个元素
# 要避免的坑
当使用不当时,导致使用者不知道它的作用域范围。
大家可能觉得线程结束后ThreadLocal应该就回收了。假设线程真的注销了确实是这种,可是事实有可能并不是如此。比如在线程池中对线程管理都是採用线程复用的方法(Web容器通常也会採用线程池)。在线程池中线程非常难结束甚至于永远不会结束。
这将意味着线程持续的时间将不可预測,甚至与JVM的生命周期一致,这就很容易导致内存泄露。在使用时要明确ThreadLocal最难以捉摸的是“不知道哪里是源头”,仅仅有知道了源头才干控制结束的部分。或者说我们从设计的角度要让ThreadLocal的set、remove有始有终,通常在外部调用的代码中使用finally来remove数据。
# 造成的后果
1.线程池中线程还在,所以threadlocal也没有销毁,导致内存泄露
2.线程池中该线程在重复使用,可能获取到上一次执行时存储的数据。导致数据不准确