在调试程序时,我们可以通过丢弃当前栈帧、使用断点表达式、强制返回当前方法、抛出异常等操作来提高我们的调试效率。
Dubbo #9490
今天帮同事看了个问题,该问题不复杂,只是表现出来没有头绪,在此简单记录。首先发现该问题是一个空指针异常,即调用方通过 Dubbo 调用消费端提供的方法时调用方的异常仅有一个空指针异常,没有其他有价值的信息。调用方的代码简化如下:
1 | @Reference |
第 6 行将抛出空指针异常,异常栈帧如下:
1 | java.lang.NullPointerException |
ConcurrentLruCache
今天看到 Spring 中的 ConcurrentLruCache 实现,本文简要记录。
1 | /** |
最为核心的方法即为 get 方法,其实现思路在上方增加了注释。关键点在于读锁那部分代码是允许多线程执行的,而我们又需要维护 queue 中节点的顺序,所以选用了线程安全的队列实现:ConcurrentLinkedDeque。唯一不理解的就是对 cache 的修改操作都被写锁保护,在当前实现中 cache 由 ConcurrentHashMap 实现,是否可以更换为 HashMap 实现呢?
关于该实现,有用户提交 issue 反馈链表中的 O(n) 扫描效率低下,建议替换为 ConcurrentLinkedHashMap,详情可参考:Revisit ConcurrentLruCache implementation · Issue #26320。
References
spring-framework/ConcurrentLruCache.java at v5.3.14 · spring-projects/spring-framework · GitHub
Why does ConcurrentLruCache in Spring still use thread-safe maps and queues instead of ordinary maps and queues even when read-write lock are used? - Stack Overflow
ConsistentHashLoadBalance
之前项目中曾使用一致性 Hash 路由请求至指定的缓存节点,关于 Dubbo 的一致性 Hash 实现可以参考 Dubbo 一致性Hash负载均衡实现剖析,源码参见 ConsistentHashLoadBalance.java at dubbo-3.0.0。其 hash 值与 Invoker 的映射关系采用 TreeMap 作为底层的数据结构,其根据当前调用查询调用者的源码如下:
1 | private final TreeMap<Long, Invoker<T>> virtualInvokers; |
Collections.SynchronizedList
当多线程并发访问一个 List 的实例时,可以使用 Collections.synchronizedList(List<T>) 将 List 的实例进行包装,其内部调用的构造函数位于 Collections.java at jdk8-b120:
1 | static class SynchronizedCollection<E> implements Collection<E>, Serializable { |
可以看出内部使用了 mutex 作为锁的对象以保证线程安全,而为什么不直接在方法上加上 synchronized 以实现相同的语义呢?是因为第二个构造函数允许用户传入锁的对象,比如用户需要使用单个锁来同步多个集合时,以实现对多集合多线程的并发访问。
在 Collections.synchronizedList(List<T>) 方法的 Java Doc 中还提到,使用迭代器时需要在外部加锁。
It is imperative that the user manually synchronize on the returned list when iterating over it:
1
2
3
4
5
6
7 List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}Failure to follow this advice may result in non-deterministic behavior.
References
Why does SynchronizedCollection assign this to a mutex? - Stack Overflow