【问题标题】:Thread issue while using Executor service使用 Executor 服务时的线程问题
【发布时间】:2013-06-20 04:04:30
【问题描述】:

我在下面的代码中遇到了线程问题。当线程执行可运行对象的 Run 方法时,它不会打印我期望的数据。

代码1--调用代码

Map<String,Object> logData = CPEMethodData.getLogDataMap();
    CatalogUpdaterLogger.getLogger().info("6 before new splunk logger log data =" + logData);
    CatalogrLogger writer = new CatalogLogger(LogType.INFO,logData,LoggerType.CATALOGUPDATER);
    LogPool.INSTANCE.submitTask(writer);//submitting writer which is a runnable object to the queue

//add one more task/writer to the queue in the same method

logData = CPEMethodData.getLogDataMap();
     CatalogUpdaterLogger.getLogger().info("11 before 3rd writer=logData "+logData);
     CatalogLogger writer2 = new CatalogLogger(LogType.INFO,logData,LoggerType.CATALOGUPDATER);

     LogPool.INSTANCE.submitTask(writer2);

在上面的代码中,我检查了 CPEMethodData.getLogDataMap() 返回的 logData 与我预期的不同。但是当可运行对象实际执行时,它仍然使用相同的数据运行...

代码 2--创建 5 个线程的线程池...

public enum LogPool {

    INSTANCE;
    private static final int nThreads = 5;
    final ExecutorService executor = Executors.newFixedThreadPool(nThreads);

    public synchronized void submitTask(Runnable task) {        
        executor.execute(task);     
    }

代码3--可运行代码

public class CatalogLogger implements Runnable {
    protected LogType logType;
    protected LoggerType loggerType;
    protected Map<String, Object> logData;
    public CatalogLogger(LogType logType, Map<String, Object> logData,
            LoggerType loggerType) {
        this.logType = logType;
        this.logData = logData;
        this.loggerType = loggerType;
    }

public void run() {
        System.out.println("running with logData " + logData);
        System.out.println(" Thread.currentThread().hashCode()  " +Thread.currentThread().hashCode());
        switch (loggerType) {
        case ORDERPROCESSING:
            logData(Logger.getLogger(ORDER_LOG));
            break;
        case CATALOGUPDATER:
            logData(Logger.getLogger(CATALOGUPDATER_LOG));
            break;
        }
    }

下面是 CPEmethoddata.getLogData

public class CPEMethodData {
private static ThreadLocal<Map<String, Object>> logDataMap = new ThreadLocal<Map<String, Object>>();

    public static Map<String,Object> getLogDataMap() {
        return logDataMap.get();
    }
public static void setOppParameters(Map<String, Object> inputParams) {
    Map<String, Object> oppStatus = logDataMap.get();
    if (oppStatus == null) {
        oppStatus = new HashMap<String, Object>();
        logDataMap.set(oppStatus);
    }
    oppStatus.put(INPUT_PARAMS, inputParams);
}

@SuppressWarnings("unchecked")
public static Map<String, Object> getOperationParameters() {
    Map<String, Object> oppStatus = logDataMap.get();
    if (oppStatus != null)
        return (Map<String, Object>) oppStatus.get(INPUT_PARAMS);
    return null;
}

}

当我运行将两个可运行文件提交到队列的代码 1 时,我希望在 run 方法的 sysout 中看到不同的 logData 内容,但是当我调试它时,我发现两次执行中的数据都是相同的......似乎第二个可运行对象干扰了第一个....任何人都可以帮助我了解这里的问题是什么。我认为我正在传递 2 个不同的 CatalogLogger 实例并且不应该引起任何问题..任何人都可以提出任何建议解决方案?

【问题讨论】:

  • 是的,您正在使用 2 个不同的 CatalogLogger 实例,但您没有使用 2 个不同的 logData 映射。这段代码目前甚至无法编译,除非恰好还有一个名为 logData 的方法。
  • CPEMethodData.getLogDataMap() 到底在做什么?它是否在每次调用时返回相同的 logData 实例?我想这会导致你的问题。可以贴一下 CPEMethodData 的代码吗?
  • @MattBall 有一个方法 logData 只在 resp 记录器中记录数据,但这不是问题......甚至在运行方法的日志中我可以看到错误的 logData 字符串打印...关于不同的 logData 映射,我认为这不是问题,因为我在传递构造函数之前打印 logData 并且它打印正确的数据。
  • 感谢您的回复..CPEMethodData.getLogDataMap 只返回地图,地图内的数据在两个调用中都不同,我在将它们发送到构造函数之前通过记录它们来确认。
  • @RenéLink 我得到了你现在想要建议的内容。我已经添加了 CPEMethoddata.getLogdataMap。你是对的,它返回的是静态 ThreadLocal.get Map 的相同实例......我想我需要创建一个返回的 Map 的新副本并将其发送给构造函数。

标签: java multithreading threadpoolexecutor


【解决方案1】:

正如@ReneLink 在对我的问题的评论中所写,CPEMethodData.getLogDataMap 正在返回 hashmap 的相同实例......所以当线程的 run 方法被执行时,hashmap 的内容正在被修改。我创建了使用 Cloner 工具的 hashmap 并将其传递给线程。 感谢@ReneLink 向我指出这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多