=== Put if absent, variante del CheckThenAct === ''A cura di Flavio Casadei Della Chiesa'' In questo schema si provvede ed inserire un elemento (di solito) in una collezione solo se questa già non lo contiene. // schema generico di put-if-absent private HashMap hm ..... public void putIfAbsent(K k , V v) { if (!hm.containsKey(k)) { hm.put(k,v); } } i problemi sono i soliti derivanti dal [[CheckThenAct]]. Nota, come in tutte le azioni composte non basta limitarsi ad aggiungere un synchronized per risolvere il problema. Per eliminare ogni sorta di problema è necessario rendere atomica l'operazione. Per far questo solo un Thread deve essere in grado di controllare la presenza o meno della chiave nella mappa e di effettuare un'eventuale sostituzione. Un esempio di soluzione può essere il seguente nel quale si istanzia una HashMap all'interno di una classe contenitrice public class InnerPIA { private final HashMap delegate = new HashMap(); public synchronized V get(K k) {return delegate.get(k);} public synchronized void put(K k, V v) { delegate.put(k,v);} public synchronized boolean containsKey(K k) {return delegate.containsKey(k);} public synchronized void putIfAbsent(K k, V v) { if (!delegate.containsKey(k) { delegate.put(k,v); } } ..... } Nel caso in cui la HashMap sia condivisa e non ''confinata'' in una classe contenitrice è necessario utilizzare un altro tipo di [[ClientSideLocking]]. In questo modo però tutte le classi che condividono la solita istanza della mappa devono utilizzare il solito protocollo. public class DelegatePIAPIA { private final Map delegate ; public DelegatePIA(Map m) { this.delegate = m; } public V get(K k) { synchronized(delegate) { return delegate.get(k); } } public void put(K k, V v) { synchronized(delegate) { delegate.put(k,v); } } public boolean containsKey(K k) { synchronized(delegate) { return delegate.containsKey(k); } } public void putIfAbsent(K k, V v) { synchronized(delegate) { if (!delegate.containsKey(k) { delegate.put(k,v); } } } ..... } In Java5, precisamente nella concurrent API, esiste un modo più immediato: utilizzare una implemantazione di una [[http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ConcurrentMap.html| ConcurrentMap]] come ad esempio la classe [[http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ConcurrentHashMap.html|ConcurrentHashMap]]. Queste dispongono di un metodo chiamato appunto ''putIfAbsent'' la cui firma è simile alla precedente; l'unica differenza è che il metodo non è void ma ritorna n elemento di tipo V. Invocare il metodo pippo = mappa.putIfAbsent(key,value); è equivalente a if (!mappa.containsKey(key)) return mappa.put(key, value); else return mappa.get(key); Se la mappa conteneva un valore precedente per la chiave ''key'' il metodo ritorna tale valore, altrimenti restituisce ''null''.