Java HashMap的死循环 以及 LRUCache的正确实现
今天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)
问题分析:
详见:http://coolshell.cn/articles/9606.html
问题解决:
采用google的ConcurrentLinkedHashMap(https://code.google.com/p/concurrentlinkedhashmap/)
- Features
- LRU 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<K, V> {
- public static final int DEFAULT_CONCURENCY_LEVEL = 64;
- private final ConcurrentLinkedHashMap<K, V> 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<K, V>().weigher(Weighers.<V> 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<K> getKeySet() {
- return map.keySet();
- }
- }
测试:
- public static void main(String[] args) {
- LRULinkedHashMap<Integer, Integer> cache = new LRULinkedHashMap<Integer, Integer>(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]
Java HashMap的死循环 以及 LRUCache的正确实现的更多相关文章
- HashMap的原理与实 无锁队列的实现Java HashMap的死循环 red black tree
http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html https://zh.wikipedia.org/wiki/%E7%BA ...
- 【转】Java HashMap的死循环
问题的症状 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题.后来,我们的程序性能有问题,所以需要变成多线程的,于是,变成多线程后到了线上,发现 ...
- Java HashMap的死循环
在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造 成Race Condition,从而导致死循环.这个事情我4 ...
- Java HashMap并发死循环
在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环.这个事情我4. ...
- 疫苗:JAVA HASHMAP的死循环
在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环.这个事情我4. ...
- Java - HashMap 多线程安全解析
HashMap多线程并发问题分析 多线程put后可能导致get死循环 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题.后来,我们的程序性能有问 ...
- 多线程下HashMap的死循环问题
多线程下[HashMap]的问题: 1.多线程put操作后,get操作导致死循环.2.多线程put非NULL元素后,get操作得到NULL值.3.多线程put操作,导致元素丢失. 本次主要关注[Has ...
- JDK(九)JDK1.7源码分析【集合】HashMap的死循环
前言 在JDK1.7&1.8源码对比分析[集合]HashMap中我们遗留了一个问题:为什么HashMap在调用resize() 方法时会出现死循环?这篇文章就通过JDK1.7的源码来分析并解释 ...
- 图解集合5:不正确地使用HashMap引发死循环及元素丢失
问题引出 前一篇文章讲解了HashMap的实现原理,讲到了HashMap不是线程安全的.那么HashMap在多线程环境下又会有什么问题呢? 几个月前,公司项目的一个模块在线上运行的时候出现了死循环,死 ...
随机推荐
- windows下前端开发工具遇到的问题总结(yeoman bower grunt)
我用的是windows环境 一毕要环境: 1:nodejs 官网:https://nodejs.org/en/ 2:由于很多国外网站国内都访问不了(如果没有设置会出现很多奇怪的错误),所有必需FQ 我 ...
- SQL内外连
分组查询select 查询信息 from 表名where 条件group by 按照列分组(可多个 ,隔开)order by 排序方式(查询信息如果列名和聚合函数同时出现,要么在聚合函数中出现,要么就 ...
- MAC使用mysql报错:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
遇到这种错误,需要重置密码. Step1:停止mysql,命令如下: $ sudo service mysql stop 或者是 $ sudo /usr/local/mysql/support-fil ...
- HPU组队赛J:Ball King(线段树)
时间限制 1 Second 内存限制 512 Mb 题目描述 HPU601球王争霸赛即将举行,ACMER纷纷参加. 现在有n个人报名参赛,每个人都有一个实力值 ai,实力值较大者获胜. 为保证比赛公 ...
- java基本数据类型的范围
System.out.println("BYTE MAX_VALUE = " + Byte.MAX_VALUE); System.out.println("BYTE MI ...
- C++ 作业 (循环链表构建队列)
/* author screen name Andromeda_Galaxy; chinese name 杨子俊 */ #include<bits/stdc++.h> using name ...
- struts2参数转换器用法
贴代码 struts的action中接收简单类型参数,struts2可以自动转化,但是复杂类型需要自定义转换器转换 public class ConvertAction extends ActionS ...
- 【BZOJ3242】【UOJ#126】【NOI2013】快餐店
NOI都是这种难度的题怎么玩嘛QAQ 原题: 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. ...
- 【java多线程】线程状态分析
一.java线程的状态 NEW: 新建状态,线程对象已经创建,但尚未启动 RUNNABLE:就绪状态,可运行状态,调用了线程的start方法,已经在java虚拟机中执行,等待获取操作系统资源如CPU, ...
- MySQL Binlog--MIXED模式下数据更新
在 Mixed 模式下,MySQL 会根据执行的每一条具体的 SQL 语句来区分对待记录的日志形式,也就是在 statement 和 row 之间选择一种.如果SQL语句为UPDATE/DELETE等 ...