誤用WeakHashMap引起的死循環cpu跑滿問題
阿新 • • 發佈:2017-11-04
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跑滿問題