1. 空间换时间,在各个框架源码中有很多地方会体现出来。
ThreadLocal 内部有一个ThreadLocalMap, 其结构是一个Entry数组,在进行get,set操作的时候会对key为null的entry进行expunge,但是因为他是通过探测法解决hash冲突的,说以每次清除完之后要对相同哈希码的key进行重新整理。时间复杂度高,空间复杂度低。
Netty中的FastThreadLocal,在每个fastThreadLocalThread线程内部有一个InternalThreadLocalMap,是一个纯数组结构,不存在所谓的冲突问题,每个新增的fastThreadLocal都加在数组后面。这就是通过牺牲空间复杂度,来减低时间复杂度。
2. 时间轮算法:
Netty中的时间轮算法,HashedWheelTimer是通过循环数组加双向链表,也就是通过增加轮次的概念来实现的。存在的问题就是,如果时间跨度大的话,会进行很多无用的推进,消耗cpu。Netty 中的时间轮是通过单线程实现的,如果在执行任务的过程中出现阻塞,会影响后面任务执行。除此之外,Netty 中的时间轮并不适合创建延迟时间跨度很大的任务,比如往时间轮内丢成百上千个任务并设置 10 天后执行,这样可能会导致链表过长 round 值很大,而且这些任务在执行之前会一直占用内存。
kafka中的时间轮算法,是通过多层次时间轮实现。那么时间轮是如何推动的呢?Netty 中是通过固定的时间间隔扫描,时候未到就等待来进行时间轮的推动。上面我们分析到这样会有空推进的情况。而 Kafka 就利用了空间换时间的思想,通过 DelayQueue,来保存每个槽,通过每个槽的过期时间排序。这样拥有最早需要执行任务的槽会有优先获取。如果时候未到,那么 delayQueue.poll 就会阻塞着,这样就不会有空推进的情况发送。