添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

昨天在开发者头条上面看的一篇文章针对Map相关的线程安全讲解说的很好,今天根据思路还原了场景(隔壁老王半夜为何尖叫?这例子说的有点让老王很忙)。

Java代码:

package com.boonya.concurrent;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
 * @author PJL
 * @note     功能描述:Add值的多线程安全问题--最优解方式是ConcurrentHashMap+Atomic*级别的原子操作
 * @package  com.boonya.concurrent
 * @filename AddConcurrent.java
 * @date     2019年4月23日 下午1:36:42
public class AddConcurrent {
	 * HashMap非线程安全
	 * @throws InterruptedException
	public static void test0() throws InterruptedException{
		 HashMap<String, Integer> map = new HashMap<String,Integer>();
	     Integer integer = new Integer(1);
	     map.put("key", integer);
	     ExecutorService executorService = Executors.newFixedThreadPool(100);
	     for (int i = 0; i < 1000; i++) {
	         executorService.execute(new Runnable() {
	             @Override
	             public void run() {
	            	 map.put("key", map.get("key").intValue()+1) ;
	     Thread.sleep(3000); //模拟等待执行结束
	     System.out.println("test0()------" + map.get("key") + "------");
	     executorService.shutdown();
	 * 严格线程安全的同步非原子操作--非线程安全
	 * @throws InterruptedException
	public static void test1() throws InterruptedException{
		 Hashtable<String, Integer> map = new Hashtable<String,Integer>();
	     Integer integer = new Integer(1);
	     map.put("key", integer);
	     ExecutorService executorService = Executors.newFixedThreadPool(100);
	     for (int i = 0; i < 1000; i++) {
	         executorService.execute(new Runnable() {
	             @Override
	             public void run() {
	            	 map.put("key", map.get("key").intValue()+1) ;
	     Thread.sleep(3000); //模拟等待执行结束
	     System.out.println("test1()------" + map.get("key") + "------");
	     executorService.shutdown();
	 * 线程安全的非原子操作--非线程安全
	 * @throws InterruptedException
	public static void test2() throws InterruptedException{
		 ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String,Integer>();
	     Integer integer = new Integer(1);
	     map.put("key", integer);
	     ExecutorService executorService = Executors.newFixedThreadPool(100);
	     for (int i = 0; i < 1000; i++) {
	         executorService.execute(new Runnable() {
	             @Override
	             public void run() {
	            	 map.put("key", map.get("key").intValue()+1) ;
	     Thread.sleep(3000); //模拟等待执行结束
	     System.out.println("test2()------" + map.get("key") + "------");
	     executorService.shutdown();
	 * 线程安全的原子操作--线程安全
	 * @throws InterruptedException
	public static void test3() throws InterruptedException{
		 ConcurrentHashMap<String, AtomicInteger> map = new ConcurrentHashMap<String,AtomicInteger>();
	     AtomicInteger integer = new AtomicInteger(1);
	     map.put("key", integer);
	     ExecutorService executorService = Executors.newFixedThreadPool(100);
	     for (int i = 0; i < 1000; i++) {
	         executorService.execute(new Runnable() {
	             @Override
	             public void run() {
	                 map.get("key").incrementAndGet();
	     Thread.sleep(3000); //模拟等待执行结束
	     System.out.println("test3()------" + map.get("key") + "------");
	     executorService.shutdown();
	public static void main(String[] args) throws InterruptedException {
		AddConcurrent.test0();
		AddConcurrent.test1();
		AddConcurrent.test2();
		AddConcurrent.test3();

输出结果:

test0()------998------
test1()------998------
test2()------413------
test3()------1001------

这个核心思想就是线程安全的原子操作一定是线程安全的。

方式1. 使用Hashtable 其实现原理是在增删改查的方法上使用了synchronized锁机制,在多线程环境下,无论是读数据,还是修改数据,在同一时刻只能有一个线程在执行synchronize方法,因为是对整个表进行锁定。所以线程越多,对该map的竞争越激烈,效率越低,不推荐使用。 方式2. 使用Collections.synchronizedMap(new Hash... APP打开 @Override public void run() { System.out.println("Before Java8, too much code for too l... APP打开 谈谈HashMap线程安全的体现HashMap的原理以及如何实现,之前在JDK7与JDK8中HashMap的实现中已经说明了。那么,为什么说HashMap线程安全的呢?它在多线程环境下,会发生什么情况呢?3个情况,1个put会同时扩容早造成死循环,2.2个put引发扩容,另外的线程有可能get不到。3.有可能2个同时put,导致1个丢失,被后1个put给覆盖掉了。         一种情况是... APP打开 import java.util.Scanner; import java.util.Map; import java.util.HashMap; public class Test { //pri APP打开 已经得到值,现在需要判断: Q290010101 1 Q290060101 1 Q290060501 1 Q290010101 2 将Q290010101的值相加,也就是 Q290010101 3 Q APP打开 在我不知道Key的名称的情况下,不管Map中值的类型,将Value全部以String类型相加到一起,结果应该是好长的一串 这种方法能不能实现 因为list有get(int),而map中的get参数就得 APP打开 public void test() { List<Person> people = new ArrayList<>(); people.add(new Person("zhangsan",20... APP打开 直接上代码,可直接运行: public static void main(String[] args) { List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); Map<String, Object> map1 = ne... APP打开