The main research in this article is the relevant content of the usage of ConcurrentMap.putIfAbsent(key,value) , as follows.
This kind of scenario is often encountered in business. A concurrent ConcurrentMap is maintained globally. Each key of the map corresponds to an object, and this object needs to be created only once. If the value corresponding to the key in the map does not exist, it will be created, otherwise it will be returned directly.
Let's look at the code first:
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; } What this code needs to do is:
We expect that each time the getInstance method is called, we must ensure that the same key returns the same Local object reference. Can this code achieve this requirement?
The answer is: the requirements can be met in a single-threaded environment, but there will be thread safety problems in a multi-threaded environment, that is, it cannot be guaranteed that the same key in concurrency will return the same Local object reference.
This is because there is a habit in the above code called put-if-absent operation [1], and this operation has a race condition:
if (locale == null) { locale = new Locale(language, country, variant); map.put(key, locale); } Because after a thread has finished judging locale == null, it is true to put value in the map. Other threads may have already done put operations on map. When doing put operations again, the locale object corresponding to the same key is overwritten, and finally the locale reference of the same key returned by the getInstance method will be inconsistent. Therefore, put-if-absent operation on Map is not safe (thread safe).
To solve this problem, java 5.0 introduced the ConcurrentMap interface, where the put-if-absent operation exists in the form of an atomic method putIfAbsent(K key, V value) . As javadoc writes:
When adding a key-value pair to the ConcurrentHashMap, it will first determine whether the key-value pair already exists.
Revise the above method:
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 form of Map (ConcurrentMap, ConcurrentHashMap), and simply uses the statement map.putIfAbsent(key, locale) . This also does not guarantee that the same key returns the same Locale object reference.
The error here is that the putIfAbsent method has a return value, and the return value is important.
Therefore, when using the putIfAbsent method, remember to judge the return value.
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); Locale tmp = map.putIfAbsent(key, locale); if (tmp != null) { locale = tmp; } } return locale; } import java.util.Map;import java.util.concurrent.ConcurrentHashMap;public class Test {public static void main(String[] args) {//Test currentHashMap.putIfAbsent() Map<long, String> clientMap = new ConcurrentHashMap<>();System.out.println("Print empty clientMap first");System.out.println("clientMap: " + clientMap);System.out.println();//Add a new record in the empty clientMap System.out.println("Add a new record in the empty clientMap");System.out.println("Add a previous clientMap: " + clientMap);long netId = 1234567L;String str1 = "michael";String result = clientMap.putIfAbsent(netId, str1);System.out.println("Add a previous clientMap: " + clientMap);System.out.println("View return value result: " + result);System.out.println();//Repeat add System.out.println("Repeat the last record");System.out.println("Before add clientMap: " + clientMap);String result2 = clientMap.putIfAbsent(netId, str1);System.out.println("After adding clientMap: " + clientMap);System.out.println("View return value result: " + result2);System.out.println();}}The above is the entire content of this article about the usage example of ConcurrentMap.putIfAbsent(key,value) and I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!