记定位一次多线程数据安全问题

背景:

项目中有一个疑难用户入库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 问题解决

原文地址:https://www.cnblogs.com/zhaiyt/p/10300449.html