zoukankan      html  css  js  c++  java
  • 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]
    

      

  • 相关阅读:
    Python匹马行天下之_循环
    Hello world!
    Python匹马天下行之python基本语法
    Python匹马行天下之python之父
    Python匹马行天下之面向对象
    Python匹马行天下之运算符
    Python匹马行天下之初识python!
    跨域问题学习记录 CORS解决的2种方法
    Linux系统运维成长记
    关于倒计时new Date().getTime()出现NaN
  • 原文地址:https://www.cnblogs.com/huangfox/p/3156812.html
Copyright © 2011-2022 走看看