Threading Issues in Java HashMap

Something happened that I'm not sure that this is possible. Obviously, this is because I saw this, but I need to find the root cause, and I was hoping you all could help.

We have a system that looks for latitude and longitude for zipcode. Instead of accessing it every time, we cache the results in a cheap HashTable cache in memory, since lat and long zip codes tend to change less often than we release.

In any case, the hash is surrounded by a class that has a get method and an add method that is synchronized. We refer to this class as a singleton.

I do not claim that this is the best setting, but it is where we are. (I plan to change to wrap the card in a call to Collections.synchronizedMap () ASAP.)

We use this cache in a multi-threaded environment, where we call 2 calls for 2 lightnings (so we can calculate the distance between them). Sometimes this happens almost at the same time, so it is very possible that both calls simultaneously access the map.

More recently, we had an incident where two different postal codes returned the same value. Assuming the initial values ​​were actually different, is there a way that writes values ​​to the map will cause the same value to be written for two different keys? Or, is there a way that 2 “receives” can cross wires and accidentally return the same value?

The only other explanation I have is that the original data was corrupted (incorrect values), but this seems very unlikely.

. ,

(PS: , , ..)

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;
}
}
+3
8

.

, lat lon , :

LatLongPair llp = InMemoryGeocodingCache.getInstance().get(ZIP1);
llp.lat = x;
llp.lon = y;

, , in-cache.

, lat lon.

P.S. (zip-code) , . TreeMap ( Collections.synchronizedMap()).

P.P.S. : , put/get , get. .

+8

, . .

, ConcurrentHashMap. , , . , ( , ).

+6

, - , , .

, hashCode, equals , HashMap (.. equals true, - , Versa).

+4

, LatLonPair ? lat lon, .

, "" "" .

+3
. Object, , -, (), . - .
+2

, , . , , .

, ( , , ):

  • ? , ?
  • , ?
0

(String ZIP) , - :

GeocodingCache cache = InMemoryGeocodingCache.getInstance();

if (!cache.has(ZIP)) {
    cache.add(ZIP, x, y);
}

, false() add(), .

, , :

public synchronized void add(String zip, double lat, double lon) {
    if (cache.containsKey(zip)) return;
    cache.put(zip, new LatLongPair(lat, lon));
}

, , , getInstance() , , InMemoryGeocodingCache ( ).

0

java HashMap:

http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html

, . , , . ( - , ; , , , .) - , , , , , "" Collections.synchronizedMap. , :

m = Collections.synchronizedMap( HashMap (...));

Or better, use java.util.concurrent.ConcurrentHashMap

0
source

Source: https://habr.com/ru/post/1698822/


All Articles