package hashtables.lockfree; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import contention.abstractions.CompositionalIntSet; /** * This lock-free concurrent hash map invokes the j.u.c.ConcurrentHashMap * from the JDK7 * * @author Vincent Gramoli * */ public class JavaHashIntSet implements CompositionalIntSet { private final ConcurrentHashMap<Integer,Integer> hash = new ConcurrentHashMap<Integer,Integer>(); private int range = 1; /** The thread-private PRNG */ final private static ThreadLocal<Random> s_random = new ThreadLocal<Random>() { @Override protected synchronized Random initialValue() { return new Random(); } }; @Override public boolean addInt(int x) { return (hash.put(s_random.get().nextInt(range), x) == null); } /* TODO: the putAll does not return a boolean indicating * whether it has updated the hashmap. There is no * addAll available in JDK1.6. */ @Override public boolean addAll(Collection<Integer> c) { HashMap<Integer, Integer> m = new HashMap<Integer, Integer>(); for (Integer x : c) { m.put(new Integer(s_random.get().nextInt(range)), x); } hash.putAll(m); return true; } @Override public boolean containsInt(int x) { return hash.containsValue(x); } @Override public void fill(int range, long size) { this.range = range; while (this.size() < size) { this.addInt(s_random.get().nextInt(range)); } } @Override public boolean removeInt(int x) { return (hash.remove(x) != null); } /* TODO: the removeAll does not exists * in JDK1.6. */ @Override public boolean removeAll(Collection<Integer> c) { ConcurrentHashMap<Integer, Integer> h = new ConcurrentHashMap<Integer, Integer>(); boolean result = false; while(true) { Iterator i = h.entrySet().iterator(); while (i.hasNext()) { Map.Entry<Integer, Integer> pairs = (Map.Entry) i.next(); h.put((Integer) pairs.getKey(), (Integer) pairs.getValue()); } for (Integer x : c) { result |= (h.remove(x) != null); } // We need a lock-free transformation // TODO check atomically that the data structure is unchanged. // TODO compare-and-swap the result //hash = h; break; } return result; } @Override public int size() { return hash.size(); } /** * This is called after the JVM warmup phase * to make sure the data structure is well initalized. * No need to do anything for this. */ public void clear() { hash.clear(); return; } @Override public Object getInt(int x) { return hash.get(x); } @Override public Object putIfAbsent(int x, int y) { if (!containsInt(x)) addInt(y); return null; } }