Read the code First: Java code public class locale { private Final static map<string, locale> map = new hashmap<string,locale > (); public static locale getinstance (String language, string country, string variant) { //... String key = some_string; locale locale = map.get (key); if (locale == null) { locale = new locale (language, Country, variAnt); map.put (key, Locale); } return locale; } // .... }
The thing to do with this code is:
Call the Map.get (key) method to determine if there is a value (Locale object) corresponding to the key in the map. If NULL is returned, there is no key-value mapping to find in the map. New a Locale object and put the new object in the map with the key. Finally return the newly created Locale object we expect to ensure that the same key returns the same Local object reference each time the GetInstance method is called. So, just look at the first piece of code, can I ask it to achieve this expectation? The answer is: in a single-threaded environment can meet the requirements, but in a multithreaded environment, there will be a thread security problem, that is not guaranteed in the case of the same concurrent key return the same Local object reference. This is because in the above code there is a custom operation called Put-if-absent [1], and this operation exists a race Condition:java code if (locale == null) { locale = new locale (language, country, variant); map.put (key, locale); } Because after a thread has finished the locale = = NULL judgment to the time when the value is actually put to the map, the other thread may have put the map in the add operation, so that when the put operation, the same key corresponding to the locale object is overwritten, the final The locale reference for the same key returned by the GetInstance method will appear inconsistent. So the put-if-absent operation on the MAP is unsafe (thread safty). To solve this problem, Java 5.0 introduces the Concurrentmap interface, in which the put-if-absent operation exists in the form of an atomic method Putifabsent (K key, V value). IsAs Javadoc wrote: Java code /** * If the specified key is not already associated * with a value, associate it with the given value. * This is equivalent to * <pre> * if (!map.containskey (key)) * return map.put (key, value); * else * Return map.get (key);</pre> * except that the action is performed atomically. * ..... */ so you can use this method instead of the operation in the above code. But it's easy to make a mistake when it comes to substitution. Take a look at the following code: Java code public class locale implements cloneable, serializable { private final static ConcurrentMap<String, Locale> map = new concurrenthashmap<string, locale> (); public static locale getinstance (string language, string country, String Variant) { //... String key = some_string; locale locale = map.get (key); if (locale == null) {   locale = new locale ( language, country, variant); map.putifabsent (Key, locale); } return locale; } // .... } This code uses the concurrent of the MAP Form (Concurrentmap, Concurrenthashmap), and simply use the statement map.putifabsent (key, Locale). This also does not guarantee that the same key returns the same Locale object reference. the error here ignores the Putifabsent method has a return value, and the return value is important 。 Still watching Javadoc:java code /** * @return the previous value associated with the specified key, or * <tt>null</tt> if there was no mapping for the key. * (A <tt >null</tt> return can also indicate that the map * previously associated <tt>null</tt > with the key, * if the implementation supports null values.) */ Returns the value if Key-value already exists (when the method is called). If the mapping of the key is not found in the map when it is called, return a null value " Therefore, it is very necessary to judge the return value when using the Putifabsent method. As shown below (jaImplementation code in the Va.util.Locale Class): Java code