Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>You really don't want to synchronize on an <code>Integer</code>, since you don't have control over what instances are the same and what instances are different. Java just doesn't provide such a facility (unless you're using Integers in a small range) that is dependable across different JVMs. If you really must synchronize on an Integer, then you need to keep a Map or Set of Integer so you can guarantee that you're getting the exact instance you want.</p> <p>Better would be to create a new object, perhaps stored in a <code>HashMap</code> that is keyed by the <code>Integer</code>, to synchronize on. Something like this:</p> <pre><code>public Page getPage(Integer id) { Page p = cache.get(id); if (p == null) { synchronized (getCacheSyncObject(id)) { p = getFromDataBase(id); cache.store(p); } } } private ConcurrentMap&lt;Integer, Integer&gt; locks = new ConcurrentHashMap&lt;Integer, Integer&gt;(); private Object getCacheSyncObject(final Integer id) { locks.putIfAbsent(id, id); return locks.get(id); } </code></pre> <p>To explain this code, it uses <code>ConcurrentMap</code>, which allows use of <code>putIfAbsent</code>. You could do this:</p> <pre><code> locks.putIfAbsent(id, new Object()); </code></pre> <p>but then you incur the (small) cost of creating an Object for each access. To avoid that, I just save the Integer itself in the <code>Map</code>. What does this achieve? Why is this any different from just using the Integer itself?</p> <p>When you do a <code>get()</code> from a <code>Map</code>, the keys are compared with <code>equals()</code> (or at least the method used is the equivalent of using <code>equals()</code>). Two different Integer instances of the same value will be equal to each other. Thus, you can pass any number of different Integer instances of "<code>new Integer(5)</code>" as the parameter to <code>getCacheSyncObject</code> and you will always get back only the very first instance that was passed in that contained that value.</p> <p>There are reasons why you may not want to synchronize on <code>Integer</code> ... you can get into deadlocks if multiple threads are synchronizing on <code>Integer</code> objects and are thus unwittingly using the same locks when they want to use different locks. You can fix this risk by using the</p> <pre><code> locks.putIfAbsent(id, new Object()); </code></pre> <p>version and thus incurring a (very) small cost to each access to the cache. Doing this, you guarantee that this class will be doing its synchronization on an object that no other class will be synchronizing on. Always a Good Thing.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload