Java游戲服維護過程中發(fā)現(xiàn)的一些細節(jié)
1.異常導致線程中斷:
游戲中啟動定時器,用來檢測地圖上掉落的物品是否到時,到時后從物品列表中清除。運行時發(fā)現(xiàn),系統(tǒng)運行一段時間后就出現(xiàn)掉落物品不消失的情況,檢查游戲邏輯沒有發(fā)現(xiàn)任何問題,當前定時器任務中連拋出異常的可能都沒有。在測試環(huán)境中使用各種方法測試都無法重現(xiàn)問題。只好萬分頭痛的去查看1GB/Hour的生產(chǎn)服運行日志,結(jié)果驚奇的發(fā)現(xiàn)用于檢測物品到時的定時器在某個時間神奇的消失了。查找定時器消失前的日志發(fā)現(xiàn)當前線程拋出了一個異常,異常拋出點還真的不是發(fā)現(xiàn)問題的定時器任務。
原因分析:
定時器timer里面其實有一個線程和一個timerTask數(shù)組,創(chuàng)建timer的時候啟動線程,然后線程負責輪詢每個timerTask是否到時,到時后執(zhí)行task中定義的操作。那么問題最終歸結(jié)為異常為什么會導致線程中斷。
標準的線程寫法是在run方法里面放置一個循環(huán),在循環(huán)結(jié)束以后,線程退出。那么如果在循環(huán)中的拋出異常而沒有捕獲,那么在跳出到循環(huán)外面之后,線程當然不會再執(zhí)行了。同樣定時器中的線程如果停止了,定時器里的所有任務當然也不會再執(zhí)行了。
2.當自動拆裝箱遇到容器類
自動拆裝箱的功能用起來很爽,各種基本數(shù)據(jù)類型和對應的封裝對象之間可以隨意轉(zhuǎn)換。但是不能忽視這個過程是有消耗資源的。
下面的代碼:
- Integer i = 1;
在編譯后是這種樣子的:
- Integer i = Integer.valueOf(1);
所以對同一個值多次拆裝箱的時候***將數(shù)據(jù)緩存一下,一點點的性能優(yōu)化也是優(yōu)化。
為什么容器類不支持基本數(shù)據(jù)類型?
好像這是一個約定俗成的概念,從學習java開始就被告訴容器類不支持基本數(shù)據(jù)類型,從來沒有想過為什么。想一想其實也很簡單,基本數(shù)據(jù)類型是游離于java萬事萬物皆對象的思想
之外的,與Object沒有繼承關(guān)系,所以要想支持只能針對每一個基本數(shù)據(jù)類型都寫一套容器類。他們是圖省事,當然都寫一套也沒有必要。
開始說正題,看下面的代碼:
- import java.util.HashMap;
- import java.util.Map;
- public class HashMapTest {
- Map<Integer, String> map;
- public static void main(String[] args)
- {
- HashMapTest test = new HashMapTest();
- test.map = new HashMap<Integer, String>();
- test.map.put(1, "s");
- test.print((short) 1);
- }
- public void print(short key)
- {
- String s = map.get(key);
- System.out.println(s);
- }
- }
這是根據(jù)真實的生產(chǎn)服bug抽取的問題代碼,當然不會寫得這么直接,要不然肯定到不了我這里了。按照我的理解hashMap的實現(xiàn)是根據(jù)對象的hashCode值進行快速定位并比較查找的,
只要hashCode相同就應該得到正確的結(jié)果。所以特意查了一下源碼發(fā)現(xiàn)返回的hashcode應該是完全相同的,這時就困惑了,看來之前的理解是有問題的。開源的東西就是有這點好處,
發(fā)現(xiàn)問題可以查看源碼尋根問底,看下面的代碼:
- public V get(Object key) {
- if (key == null)
- return getForNullKey();
- int hash = hash(key.hashCode());
- for (Entry<K,V> e = table[indexFor(hash, table.length)];
- e != null;
- e = e.next) {
- Object k;
- if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
- return e.value;
- }
- return null;
- }
Integer的equals方法:
- public boolean equals(Object obj) {
- if (obj instanceof Integer) {
- return value == ((Integer)obj).intValue();
- }
- return false;
- }
還是有一個問題,為什么get方法里面的參數(shù)不用泛型呢,如果用了泛型不就不會出現(xiàn)這種問題了。
原文鏈接:http://www.cnblogs.com/waynell/archive/2012/05/05/2444232.html
【編輯推薦】