誤用WeakHashMap引起的死循環cpu跑滿問題


最近使用mvel 2.2.0.Final,出現一次cpu跑滿,經過線程棧分析,發現是誤用WeakHashMap引起的。

故障現場:

看WeakHashMap源碼:

    public V get(Object key) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int index = indexFor(h, tab.length);
        Entry<K,V> e = tab[index];
        while (e != null) {
            if (e.hash == h && eq(k, e.get()))
                return e.value;
            e = e.next;
        }
        return null;
    }

 

 

線程在WeakHashMap的get方法里面出不來了,一直在while循環里面。

多線程並發get和put,fullgc或gc的時候可能會出現。
因為gc會把對象給清理掉,然后get方法內的while循環一直找不到eq的對象,循環出不來。

 

WeakHashMap類已經說明了這個類不是線程安全的。在[2.1.8.Final,~]以上修復了,除了2.2.0.Final,修復詳情

問題復現:

import java.util.Map;
import java.util.Random;
import java.util.WeakHashMap;

public class WeakHashMapTest {

    Thread thread = new Thread(new Runnable() {

        @Override
        public void run() {
        }
    });

    public static void main(String[] args) throws InterruptedException {
        Random random = new Random();
        //        Map<String, String> weak = Collections.synchronizedMap(new WeakHashMap<>());//OK
        Map<String, String> weak = new WeakHashMap<>();
        for (int i = 0; i < 10; i++) {
            weak.put(new String("" + i), "" + i);
        }
        for (int i = 0; i < 20; i++) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    StringBuffer sb = new StringBuffer();
                    for (int k = 0; k < 200; k++) {
                        sb.append(weak.get(new String("" + (k) % 10)));
                        if (k % 17 == 0) {
                            System.gc();
                        }
                        int nextInt = random.nextInt(10);
                        weak.put(new String("" + nextInt), "" + nextInt);
                    }
                    System.out.println("end:" + sb.toString());
                }
            }).start();
        }
        System.gc();
        System.out.println("sleep");
        Thread.sleep(10000);
        System.out.println("exit");
        System.out.println("exit2");
    }

    static void test1() {
        Map<String, String> weak = new WeakHashMap<>();
        weak.put(new String("1"), "1");
        weak.put(new String("2"), "2");
        weak.put(new String("3"), "3");
        weak.put(new String("4"), "4");
        weak.put(new String("5"), "5");
        weak.put(new String("6"), "6");
        System.out.println(weak.size());
        System.gc(); //手動觸發 Full GC
        try {
            Thread.sleep(50); //我的測試中發現必須sleep一下才能看到不一樣的結果
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(weak.size());
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM