记定位一次多线程数据安全问题
背景:
项目中有一个疑难用户入库task,该task是全国范围共用的,事件单是湖北提出的,说是入库的数据出现了重复的,一开始就按照特殊省份对待定位,结果跑偏了
问题很简单,但是很难发现:现帖出问题代码

TaskEngine是线程池工具类,这里是异步调用入库接口,数据封装在inputObject中,所有线程共享inputObject,由于入库逻辑较为复杂,所以比较耗时,多次异步调用,每次循环只
会覆盖掉inputObject中封装的数据,所以如果接口很慢的时候,就会出现最后一个线程中的数据覆盖掉前面线程中的数据,导致出现同一数据出现多次入库。
为更直观的解释上面问题,请看如下例子。
1.线程类
import java.util.Map;
/**
* @ClassName TestThread
* @Description screenShot 梦想家
* @Author Zhai XiaoTao https://www.cnblogs.com/zhaiyt
* @Date 2019/1/21 17:12
* @Version 1.0
*/
public class TestThread implements Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
private Map<String, Object> param;
public TestThread(Map param) {
this.param = param;
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.param);
}
}
2.测试类
package com.zyt.creenshot.service.impl; import com.zyt.creenshot.service.thread.TestThread; import com.zyt.creenshot.util.TaskEngine; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @ClassName TestServiceImpl * @Description screenShot 梦想家 * @Author Zhai XiaoTao https://www.cnblogs.com/zhaiyt * @Date 2019/1/15 17:34 * @Version 1.0 */ @Service public class TestServiceImpl{ public static void main(String[] args) { testTask(); } public static void testTask(){ List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); list.add("6"); list.add("7"); list.add("8"); list.add("9"); Map<String,Object> param = new HashMap<>(); for (int i = 0 ;i <3 ; i++) { List<String> sublist = list.subList(i * 3, 3*(i+1)); param.put("subList",sublist); TaskEngine.getInstance().submit(new TestThread(param)); } } }
3.运行输出

4.修改测试类
package com.zyt.creenshot.service.impl; import com.zyt.creenshot.mapper.TestMapper; import com.zyt.creenshot.service.ITestService; import com.zyt.creenshot.service.thread.TestThread; import com.zyt.creenshot.util.TaskEngine; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @ClassName TestServiceImpl * @Description screenShot 梦想家 * @Author Zhai XiaoTao https://www.cnblogs.com/zhaiyt * @Date 2019/1/15 17:34 * @Version 1.0 */ @Service public class TestServiceImpl implements ITestService { @Autowired(required = false) private TestMapper testMapper; @Override public List test(){ List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); list.add("6"); list.add("7"); list.add("8"); list.add("9"); List map = testMapper.selectByCount(list); System.out.println(map); return map; } public static void main(String[] args) { testTask(); } public static void testTask(){ List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); list.add("6"); list.add("7"); list.add("8"); list.add("9"); Map<String,Object> param = new HashMap<>(); for (int i = 0 ;i <3 ; i++) { List<String> sublist = list.subList(i * 3, 3*(i+1)); Map map = (HashMap<String, Object>)((HashMap<String, Object>)param).clone(); map.put("subList",sublist); TaskEngine.getInstance().submit(new TestThread(map)); } } }
5.运行测试

Over 问题解决

浙公网安备 33010602011771号