Something happened that I'm not sure should be possible. Obviously it is, because I've seen it, but I need to find the root cause & I was hoping you all could help.
We have a system that looks up latitude & longitude for a zipcode. Rather than access it every time, we cache the results in a cheap in-memory HashTable cache, since the lat & long of a zip code tend to change less often than we release.
Anyway, the hash is surrounded by a class that has a "get" and "add" method that are both synchronized. We access this class as a singleton.
I'm not claiming this is the best setup, but it's where we're at. (I plan to change to wrap the Map in a Collections.synchronizedMap() call ASAP.)
We use this cache in a multi-threaded environment, where we thread 2 calls for 2 zips (so we can calculate the distance between the two). These sometimes happen at very nearly the same time, so its very possible that both calls access the map at the same time.
Just recently we had an incident where two different zip codes returned the same value. Assuming that the initial values were actually different, is there any way that writing the values into the Map would cause the same value to be written for two different keys? Or, is there any way that 2 "gets" could cross wires and accidentally return the same value?
The only other explanation I have is that the initial data was corrupt (wrong values), but it seems very unlikely.
Any ideas would be appreciated. Thanks, Peter
(PS: Let me know if you need more info, code, etc.)
public class InMemoryGeocodingCache implements GeocodingCache
{
private Map cache = new HashMap();
private static GeocodingCache instance = new InMemoryGeocodingCache();
public static GeocodingCache getInstance()
{
return instance;
}
public synchronized LatLongPair get(String zip)
{
return (LatLongPair) cache.get(zip);
}
public synchronized boolean has(String zip)
{
return cache.containsKey(zip);
}
public synchronized void add(String zip, double lat, double lon)
{
cache.put(zip, new LatLongPair(lat, lon));
}
}
public class LatLongPair {
double lat;
double lon;
LatLongPair(double lat, double lon)
{
this.lat = lat;
this.lon = lon;
}
public double getLatitude()
{
return this.lat;
}
public double getLongitude()
{
return this.lon;
}
}