博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java HashMap的死循环 以及 LRUCache的正确实现
阅读量:6915 次
发布时间:2019-06-27

本文共 4887 字,大约阅读时间需要 16 分钟。

今天RP爆发,16核服务器load飙到30多,cpu使用情况全部99%以上。

从jstack中分析发现全部线程都堵在map.transfer处,如下:

"pool-10-thread-23" prio=10 tid=0x00007fb190003800 nid=0x6350 runnable [0x00007fb64554b000]   java.lang.Thread.State: RUNNABLE        at java.util.LinkedHashMap.transfer(LinkedHashMap.java:253)        at java.util.HashMap.resize(HashMap.java:564)        at java.util.HashMap.addEntry(HashMap.java:851)        at java.util.LinkedHashMap.addEntry(LinkedHashMap.java:427)        at java.util.HashMap.put(HashMap.java:484)

 

定位问题:

LinkedHashMap非线程安全(本来是借用linkedHashMap实现LRUCache)

问题分析:

详见:

问题解决:

采用google的ConcurrentLinkedHashMap()

FeaturesLRU page replacement policy (currently being upgraded to LIRS).Equivalent performance to ConcurrentHashMap under load.Can bound by the size of the values (e.g. Multimap cache).Can notify a listener when an entry is evicted.

cassandra也在concurrentLinkedHashMap的基础上实现了LRUCache,代码如下(微调):

/** *  * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements.  See the NOTICE file * distributed with this work for additional information * regarding copyright ownership.  The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License.  You may obtain a copy of the License at *  *   http://www.apache.org/licenses/LICENSE-2.0 *  * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied.  See the License for the * specific language governing permissions and limitations * under the License. *  */import java.util.Set;import java.util.concurrent.atomic.AtomicLong;import com.googlecode.concurrentlinkedhashmap.Weighers;import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;public class LRULinkedHashMap
{ public static final int DEFAULT_CONCURENCY_LEVEL = 64; private final ConcurrentLinkedHashMap
map; private final AtomicLong requests = new AtomicLong(0); private final AtomicLong hits = new AtomicLong(0); private final AtomicLong lastRequests = new AtomicLong(0); private final AtomicLong lastHits = new AtomicLong(0); private volatile boolean capacitySetManually; public LRULinkedHashMap(int capacity) { this(capacity, DEFAULT_CONCURENCY_LEVEL); } public LRULinkedHashMap(int capacity, int concurrency) { map = new ConcurrentLinkedHashMap.Builder
().weigher(Weighers.
singleton()) .initialCapacity(capacity).maximumWeightedCapacity(capacity) .concurrencyLevel(concurrency).build(); } public void put(K key, V value) { map.put(key, value); } public V get(K key) { V v = map.get(key); requests.incrementAndGet(); if (v != null) hits.incrementAndGet(); return v; } public V getInternal(K key) { return map.get(key); } public void remove(K key) { map.remove(key); } public long getCapacity() { return map.capacity(); } public boolean isCapacitySetManually() { return capacitySetManually; } public void updateCapacity(int capacity) { map.setCapacity(capacity); } public void setCapacity(int capacity) { updateCapacity(capacity); capacitySetManually = true; } public int getSize() { return map.size(); } public long getHits() { return hits.get(); } public long getRequests() { return requests.get(); } public double getRecentHitRate() { long r = requests.get(); long h = hits.get(); try { return ((double) (h - lastHits.get())) / (r - lastRequests.get()); } finally { lastRequests.set(r); lastHits.set(h); } } public void clear() { map.clear(); requests.set(0); hits.set(0); } public Set
getKeySet() { return map.keySet(); }}

  

测试:

public static void main(String[] args) {        LRULinkedHashMap
cache = new LRULinkedHashMap
(5); Random r = new Random(); for (int i = 0; i < 10; i++) { int k = r.nextInt(10); System.out.println("input " + k); cache.put(k, k); System.out.println(cache.getKeySet().toString()); } }

结果如下:

input 1[1]input 0[0, 1]input 3[0, 1, 3]input 4[0, 1, 4, 3]input 2[0, 2, 1, 4, 3]input 2[0, 2, 1, 4, 3]input 4[0, 2, 1, 4, 3]input 8[0, 8, 2, 4, 3]input 0[0, 8, 2, 4, 3]input 2[0, 8, 2, 4, 3]

  

 

转载地址:http://qixcl.baihongyu.com/

你可能感兴趣的文章
VS输出窗口(output view)的小技巧--文件行号字符定位
查看>>
14.4. Example
查看>>
[UIView beginAnimations:context:]与[UIView animateWithDuration:animations:]值得注意的一个区别...
查看>>
U3D的飞船太空射击例子中,使用coroutine
查看>>
Alibaba Cloud MaxCompute vs. AWS Redshift vs. Azure SQL Data Warehouse
查看>>
52.2. group by
查看>>
浅谈数据库用户表结构设计,第三方登录
查看>>
JS冒泡事件 与 事件捕获
查看>>
NetSetMan IP地址切换工具
查看>>
Lind.DDD敏捷领域驱动框架~Lind.DDD各层介绍
查看>>
单片机不同晶振怎么计算延迟时间?
查看>>
第 15 章 Div+CSS页面设计
查看>>
龙珠激斗大冒险掷筛子算法
查看>>
第 46 章 Regular expression (正则表达式)
查看>>
入坑IT都快十年了
查看>>
【spring Boot】spring boot获取资源文件的三种方式【两种情况下】
查看>>
(转) 机器学习很有趣Part6:怎样使用深度学习进行语音识别
查看>>
ASP.NET遇到HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容
查看>>
Android Gradle 自定义Task 详解
查看>>
数据结构之树、森林和二叉树的转换
查看>>