public static void demo1() { final Map<String, Integer> count = new ConcurrentHashMap<>(); final CountDownLatch endLatch = new CountDownLatch(2); Runnable task = new Runnable() { @Override public void run() { for (int i = 0; i < 5; i++) { Integer value = count.get("a"); if (null == value) { count.put("a", 1); } else { count.put("a", value + 1); } } endLatch.countDown(); } }; new Thread(task).start(); new Thread(task).start(); try { endLatch.await(); System.out.println(count); } catch (Exception e) { e.printStackTrace(); } }demo1是两个线程操作ConcurrentHashMap,意图将value变为10。但是,因为多个线程用相同的key调用时,很可能会覆盖相互的结果,造成记录的次数比实际出现的次数少。
V putIfAbsent(K key, V value) 如果key对应的value不存在,则put进去,返回null。否则不put,返回已存在的value。 boolean remove(Object key, Object value) 如果key对应的值是value,则移除K-V,返回true。否则不移除,返回false。 boolean replace(K key, V oldValue, V newValue) 如果key对应的当前值是oldValue,则替换为newValue,返回true。否则不替换,返回false。于是对demo1进行改进:
public static void demo1() { final Map<String, Integer> count = new ConcurrentHashMap<>(); final CountDownLatch endLatch = new CountDownLatch(2); Runnable task = new Runnable() { @Override public void run() { Integer oldValue, newValue; for (int i = 0; i < 5; i++) { while (true) { oldValue = count.get("a"); if (null == oldValue) { newValue = 1; if (count.putIfAbsent("a", newValue) == null) { break; } } else { newValue = oldValue + 1; if (count.replace("a", oldValue, newValue)) { break; } } } } endLatch.countDown(); } }; new Thread(task).start(); new Thread(task).start(); try { endLatch.await(); System.out.println(count); } catch (Exception e) { e.printStackTrace(); } }由于ConcurrentMap中不能保存value为null的值,所以需要处理不存在和已存在两种情况,不过可以使用AtomicInteger来替代。
public static void demo1() { final Map<String, AtomicInteger> count = new ConcurrentHashMap<>(); final CountDownLatch endLatch = new CountDownLatch(2); Runnable task = new Runnable() { @Override public void run() { AtomicInteger oldValue; for (int i = 0; i < 5; i++) { oldValue = count.get("a"); if (null == oldValue) { AtomicInteger zeroValue = new AtomicInteger(0); oldValue = count.putIfAbsent("a", zeroValue); if (null == oldValue) { oldValue = zeroValue; } } oldValue.incrementAndGet(); } endLatch.countDown(); } }; new Thread(task).start(); new Thread(task).start(); try { endLatch.await(); System.out.println(count); } catch (Exception e) { e.printStackTrace(); } }