2011-09-09 18 views
2

私のアプリケーションは、SpringとHibernateフレームワークのTomcatで動作しています。 EHCacheは、サービスレベルでキャッシュプロバイダとして使用されます。つまり、サービスクラスによって作成されたオブジェクトがキャッシュに格納されます。 (Daoオブジェクトを休止しない)。マルチスレッド環境のキャッシュコレクション上の無限ループ

これらのキャッシュオブジェクトには、いくつかのコレクションオブジェクト(HashSet、ArrayList、HashMap)があります。それらのうちのどれも同期されたコレクションではありません。すべてスレッドセーフではありませんが、キャッシュに入れた後はアプリケーションによって変更されません。

このコレクションをループすると、多くの場合無限ループが検出されました。いくつかのループはイテレータループであり、他のものはintインデックス上のループ実行のために古いものです。

私は、HashSetをCollections.synchronizedSet(new HashSet())に置き換えることによって、無限ループを克服することができました。しかし、通常のHashSetをアプ​​リケーションで変更することはないので、実際の問題を理解できません。 (EHCacheでそれらを変更しますか?)

スレッドセーフでないコレクションを使用している場合は、ここで問題がある場合は、私に説明してください。

public class HotelDetails implements Serializable { /*Objects in the cache */ 
private static final long serialVersionUID = 1L; 
..... 

private Set<String> facilities = new HashSet<String>(); 
} 

ループが一回のHashSetを置き換える、問題は

public class HotelDetails implements Serializable { /*Objects in the cache */ 
private static final long serialVersionUID = 1L; 
..... 

private Set<String> facilities = Collections.synchronizedSet(new HashSet<String>()); 
} 

を解決し、これは別の1

private int getRatesStartIndex(GsRoomRate gsRoomRate, List<GsRate> gsRates, Date travelStart) { 
    Integer startIndex = gsRoomRate.getGsRateIndexes().get(travelStart); 
    if (startIndex==null) { 
     for (startIndex=0; startIndex<gsRates.size(); startIndex++) { 
      GsRate gsRate = gsRates.get(startIndex); 
      if (travelStart.between(gsRate.getStartDate(), gsRate.getEndDate())) { 
       gsRoomRate.getGsRateIndexes().put(travelStart, startIndex); 
       break; 
      } 
     } 
     if (startIndex>=gsRates.size()) startIndex = 0; 
    } 

    return startIndex; 
} 


public class GsRoomRate implements Serializable { /*Objects in the cache */ 
    private static final long serialVersionUID = 1L; 
    private List<GsRate> gsRates = new ArrayList<GsRate>(); 
    private Map<Date, Integer> gsRateIndexes = new HashMap<Date, Integer>(); 
} 

public class GsRate implements Serializable { /*Objects in the cache */ 

    private static final long serialVersionUID = 1L; 

    private RBADate startDate; 
    private RBADate endDate; 
} 
+3

いくつかのコードを表示してください... –

+0

同期セットに変更した後、あなたの呼び出しは戻ってきますか?どのようにあなたは無限ループに入っていることを知っていますか?ヒープスペースが足りなくなっているため、あなたはあなたが無限ループにいると思うことを示しているようです...? –

答えて

1

で無限に実行し、ヒープ

if (hotelDetails.getFacilities() != null && hotelDetails.getFacilities().size() > 0) { 
for (String fac : hotelDetails.getFacilities()) { 
    TFacility f = of.createTFacility(); 
    f.setCode(fac); 
    f.setValue(fac); 
    facilities.getFacility().add(f); 
} 
} 

を吹き消す続きEHCacheはどのような方法でもオブジェクトを変更できます。ただし、ディスクベースのキャッシュ(ディスクにオーバーフローする可能性のあるキャッシュ)がある場合、EHCacheはオブジェクトをシリアル化し、ディスクに書き込み、必要に応じて再度ロードします。

あなたのオブジェクトをシリアル化する問題があるのであれば、あなたがこの問題を引き起こす可能性がありますが、それはあなたの問題のように感じることはありません、波及するEHCacheなどを設定しています。

私は、同じIDを持ついくつかのオブジェクトがキャッシュに入れられるか、オブジェクトが完全に初期化される前にキャッシュに追加されると考えています。

これをデバッグする方法は?

  1. 誰かがキャッシュに追加した後にコレクションを変更しようとすると、エラーを取得するにはCollections.unmodifiable*()を使用してください。

  2. コレクションのhashCode()を保存して検証します。 hashCode()は、a)コレクションが変更された場合、またはb)コレクション内のオブジェクトのhashCode()が変更された場合に変更されます。

特に後者は、予期せぬ問題の素晴らしい源です:人々は、セット/マップにオブジェクトを追加、()hashCodeを非finalフィールドを使用すると奇数のことが起こります。

+0

ありがとうAaron ...もう少し調査したところ、HashMapが問題を引き起こしていることが分かりました。 get()メソッドの内部ループは無限に実行されます。この問題に関する多くの情報を見つけることができます。しかし、直接の答えではありません。 HashMapが変更されない場合、マルチスレッドアプリケーションでHashMapを使用するのは安全ですか? – Rasika

+0

はい、すべてのJava構造は変更されていない限り安全です。あなたの説明は、スレッドAが地図からデータを取得している間にスレッドAがデータを追加するように聞こえます。それはあらゆる種類の問題を引き起こす可能性があります。 ConcurrentHashMapを試して問題が解決されているかどうか確認してください。または上記の私の答えによると 'Collections.unmodifiable *()'。 –