Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Based on the <a href="https://stackoverflow.com/a/5640192/337221">answer of McDowell</a> and his class <a href="http://illegalargumentexception.blogspot.ch/2008/04/java-synchronizing-on-transient-id.html" rel="nofollow noreferrer">IdMutexProvider</a>, I have written the generic class <code>LockMap</code> that uses <a href="http://docs.oracle.com/javase/6/docs/api/java/util/WeakHashMap.html" rel="nofollow noreferrer">WeakHashMap</a> to store lock objects. <code>LockMap.get()</code> can be used to retrieve a lock object for a key, which can then be used with the Java <code>synchronized (...)</code> statement to apply a lock. Unused lock objects are automatically freed during garbage collection.</p> <pre><code>import java.lang.ref.WeakReference; import java.util.WeakHashMap; // A map that creates and stores lock objects for arbitrary keys values. // Lock objects which are no longer referenced are automatically released during garbage collection. // Author: Christian d'Heureuse, www.source-code.biz // Based on IdMutexProvider by McDowell, http://illegalargumentexception.blogspot.ch/2008/04/java-synchronizing-on-transient-id.html // See also https://stackoverflow.com/questions/5639870/simple-java-name-based-locks public class LockMap&lt;KEY&gt; { private WeakHashMap&lt;KeyWrapper&lt;KEY&gt;,WeakReference&lt;KeyWrapper&lt;KEY&gt;&gt;&gt; map; public LockMap() { map = new WeakHashMap&lt;KeyWrapper&lt;KEY&gt;,WeakReference&lt;KeyWrapper&lt;KEY&gt;&gt;&gt;(); } // Returns a lock object for the specified key. public synchronized Object get (KEY key) { if (key == null) { throw new NullPointerException(); } KeyWrapper&lt;KEY&gt; newKeyWrapper = new KeyWrapper&lt;KEY&gt;(key); WeakReference&lt;KeyWrapper&lt;KEY&gt;&gt; ref = map.get(newKeyWrapper); KeyWrapper&lt;KEY&gt; oldKeyWrapper = (ref == null) ? null : ref.get(); if (oldKeyWrapper != null) { return oldKeyWrapper; } map.put(newKeyWrapper, new WeakReference&lt;KeyWrapper&lt;KEY&gt;&gt;(newKeyWrapper)); return newKeyWrapper; } // Returns the number of used entries in the map. public synchronized int size() { return map.size(); } // KeyWrapper wraps a key value and is used in three ways: // - as the key for the internal WeakHashMap // - as the value for the internal WeakHashMap, additionally wrapped in a WeakReference // - as the lock object associated to the key private static class KeyWrapper&lt;KEY&gt; { private KEY key; private int hashCode; public KeyWrapper (KEY key) { this.key = key; hashCode = key.hashCode(); } public boolean equals (Object obj) { if (obj == this) { return true; } if (obj instanceof KeyWrapper) { return ((KeyWrapper)obj).key.equals(key); } return false; } public int hashCode() { return hashCode; }} } // end class LockMap </code></pre> <p>Example of how to use the LockMap class:</p> <pre><code>private static LockMap&lt;String&gt; lockMap = new LockMap&lt;String&gt;(); synchronized (lockMap.get(name)) { ... } </code></pre> <p>A simple test program for the LockMap class:</p> <pre><code>public static Object lock1; public static Object lock2; public static void main (String[] args) throws Exception { System.out.println("TestLockMap Started"); LockMap&lt;Integer&gt; map = new LockMap&lt;Integer&gt;(); lock1 = map.get(1); lock2 = map.get(2); if (lock2 == lock1) { throw new Error(); } Object lock1b = map.get(1); if (lock1b != lock1) { throw new Error(); } if (map.size() != 2) { throw new Error(); } for (int i=0; i&lt;10000000; i++) { map.get(i); } System.out.println("Size before gc: " + map.size()); // result varies, e.g. 4425760 System.gc(); Thread.sleep(1000); if (map.size() != 2) { System.out.println("Size after gc should be 2 but is " + map.size()); } System.out.println("TestLockMap completed"); } </code></pre> <p>If anyone knows a better way to automatically test the LockMap class, please write a comment.</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