1. 程式人生 > >誤用WeakHashMap引起的死循環cpu跑滿問題

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

interrupt 除了 oid put cti png catch buffer 線程棧

最近使用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()); } }

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