|
I downloaded the source for this and looked at it. I believe that on a weakly consistent hardware platform, using the fast path may open you up to possible problems. NOTE: I don't believe there is a problem that I can identify in this code today because you're all probably running on strongly consistent hardware. i.e. Below, where the code in the put() method FIRST stores the object, THEN stores the map variable. When thread 2 loads the map variable, you can be sure that the variables modified previous to the map variable were stored. Eventually, you'll be on weakly consistent hardware (not just iSeries, but other platforms too), and in my mind, its better to do it right and not focus on which hardware platform you're on. So... What sort of problems? I can come up with a few. Lets look at only two methods of this guy (source excerpted below for containsValue() and put()), and assume there are many reader threads (using containsValue() and one writer thread (using put()). FastHashMap m = new FastHashMap(); Prime with some entries, not including "Threads". Thread 1: while (!m.containsValue("Threads")) { // No-op } // Continue Thread 2: // Unrelated work for a while m.put("Threads"); // Continue unrelated work Some possible outcomes: 1) After Thread 2 inserts "Threads" into the HashMap, Thread 1 continues to spin, 'for a while' using the old version of m.map, because although Thread 2 used 'synchronized', thread 1 did not. i.e. thread 1 doesn't ensure that it will load the new m.map variable from storage. 2) After Thread 2 inserts "Threads" into the HashMap, Thread 1 sees the update of m.map variable right away (by chance, not due to using a synchronized keyword to ensure a reload of the variable). Thread 1 then using the get() method on it, still doesn't see the updates to HashMap.count nor HashMap.table, so it doesn't retrieve the value (gets null). 3) Alternative to #2 is that some combination of values of HashMap instance variables or HashMap.table (Entry object variables) are not flushed, and this causes some 'worse' form of error, like a NullPointerException. >From the code in Hashmap.get() this looks unlikely, but the combinations of what could be theoretically stored is pretty complex, so I wouldn't rule it out. So, it may just be that the old version of the map is used and the objects inserted are not seen (as it looks like was intended) by the reader thread right away. But, it could also easily be that the new version of the map IS used before the object insertion is completely flushed to storage. Looking through the code for Hashmap, it looks like this will STILL be ok, resulting in a worst case of simply a return of null (object not found). However, the complexity of which instance variables were flushed from HashMap and in the Entry objects and which variables were not is pretty large. So, its hard to be sure. That's why synchronization is better/safer and easier than trying to micro-analyze most of the time. public class FastHashMap extends HashMap { protected HashMap map = null; protected boolean fast = false; public Object put(Object key, Object value) { if (fast) { synchronized (this) { HashMap temp = (HashMap) map.clone(); Object result = temp.put(key, value); map = temp; return (result); } } else { synchronized (map) { return (map.put(key, value)); } } } public boolean containsValue(Object value) { if (fast) { return (map.containsValue(value)); } else { synchronized (map) { return (map.containsValue(value)); } } } } public class HashMap extends blah blah { // Instance variables of interest to this guy... private transient Entry table[]; private transient int count; public Object put(Object key, Object value) { // PUT IS PRETTY BIG. I'VE EXCERPTED HERE .... // Makes sure the key is not already in the HashMap. Entry tab[] = table; int hash = 0; int index = 0; .... // Creates the new entry. Entry e = new Entry(hash, key, value, tab[index]); tab[index] = e; count++; return null; } public boolean containsValue(Object value) { Entry tab[] = table; if (value==null) { for (int i = tab.length ; i-- > 0 ;) for (Entry e = tab[i] ; e != null ; e = e.next) if (e.value==null) return true; } else { for (int i = tab.length ; i-- > 0 ;) for (Entry e = tab[i] ; e != null ; e = e.next) if (value.equals(e.value)) return true; } return false; } } "The stuff we call "software" is not like anything that human society is used to thinking about. Software is something like a machine, and something like mathematics, and something like language, and something like thought, and art, and information... but software is not in fact any of those other things." Bruce Sterling - The Hacker Crackdown Fred A. Kulack - IBM eServer iSeries - Enterprise Application Solutions ERP, Java DB2 access, Jdbc, JTA, etc... IBM in Rochester, MN (Phone: 507.253.5982 T/L 553-5982) mailto:kulack@us.ibm.com Personal: mailto:kulack@magnaspeed.net AIM Home:FKulack AIM Work:FKulackWrk MSN Work: fakulack@hotmail.com "David Morris" <David.Morris@plu To: <java400-l@midrange.com> mcreek.com> cc: Sent by: Subject: RE: FW: Java Vs RPG on iSeries java400-l-admin@m idrange.com 09/20/2002 03:15 PM Please respond to java400-l I'm always scared that there is a better way or that some gremlin that will take 50 hours to debug is hiding in my code. I read the reference you posted and am wondering how safe the following class is. I have used this quite a bit particularly for cache type implementations: http://jakarta.apache.org/commons/collections/api/org/apache/commons/collections/FastHashMap.html I have never run into any synchronization problems with this class or some of its related classes, but it now seems it could be dangerous to switch between the fast and slow modes, which occurs on a cache miss. David Morris >>> kulack@us.ibm.com 09/20/02 11:33AM >>> One of my co-workers said I was scaring people... So I'm probably done now. 8-) Sorry about that. Don't be scared, just be cautious, threads programming is a little more difficult (even in Java) than many people who love Java would have you believe. Just remember to use synchronized {} when sharing data... _______________________________________________ This is the Java Programming on and around the iSeries / AS400 (JAVA400-L) mailing list To post a message email: JAVA400-L@midrange.com To subscribe, unsubscribe, or change list options, visit: http://lists.midrange.com/cgi-bin/listinfo/java400-l or email: JAVA400-L-request@midrange.com Before posting, please take a moment to review the archives at http://archive.midrange.com/java400-l.
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.