ConcurrentHashMap使用示例

【集合】 专栏收录该内容
19 篇文章 0 订阅

       ConcurrentHashMap是并发效率更高的Map,用来替换其他线程安全的Map容器,比如Hashtable和Collections.synchronizedMap。实际上,并发执行时,线程安全的容器只能保证自身的数据不被破坏,但无法保证业务的行为是否正确。错误的理解这里的线程安全,不恰当的使用ConcurrentHashMap,往往会导致出现问题。

举个例子:
	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调用时,很可能会覆盖相互的结果,造成记录的次数比实际出现的次数少。
    当然可以用锁解决这个问题,但是也可以使用ConcurrentMap定义的方法:
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();
	}
}







  • 6
    点赞
  • 0
    评论
  • 8
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值