单元测试问题中的静态java HashMap并发

des*_*pot 1 java concurrency unit-testing hashmap

我有一个类(让我们称之为XClass),它有一个方法(让我们称之为xMethod),我正在测试.它还包含一个:

private static Map<String, String> map = new HashMap<String, String>();
Run Code Online (Sandbox Code Playgroud)

在我的单元测试的安装方法中,我有:

ReflectionTestUtils.setField(xClass, "map", map, null);
Run Code Online (Sandbox Code Playgroud)

在测试方法中,我创建了几个(在我的例子中为8个)线程.他们的run方法调用xClass.xMethod.此方法更改静态映射变量.方法xMethod,应该调用map.containsKey()map.get()和map.put()8次.它没有做任何删除.此方法也不会创建任何新线程,因此一旦线程完成xMethod后就不应更改映射.我等待所有线程完成(正常或异常).比我查看地图

int mapSize = map.size();
assertEquals("map:" + map, 8, mapSize);
Run Code Online (Sandbox Code Playgroud)

它在这里失败了:

java.lang.AssertionError:map:{3 = x1,2 = x2,1 = x3,7 = x4,6 = x5,5 = x6,4 = x7,8 = x8}预期:<8>但是:< 7>

我通过使用ConcurrentHashMap解决了这个问题,但我仍然对这个问题感到困惑.所有8个线程完成之后怎么可能,因为地图表现得很奇怪(size()返回7但toString()打印8个实体)?我会理解是否有7个entites并且size()方法给出7,但是地图中有8个实体.这怎么可能?!

顺便说一句,我通过几种方式检查了线程的终止:
1.检查Thread.State.TERMINATED.
2.我在方法返回之前打印了一条简单的消息,在完成线程后打印了一条简单的消息(并检查没有抛出异常.8条消息总是在第9条之前写入(在线程"完成"后的测试中).
3.甚至完成了一个简单的线程,在run方法中包含以下逻辑:

        public void run() {
                try {
                        obj = xClass.xMethod();
                } catch (Exception e) {
                        exc = e;
                }
                finished = true;
        }
Run Code Online (Sandbox Code Playgroud)

比我只能无限循环,直到所有线程都完成了== true.

所有这些都意味着在我继续断言和检查地图之前完成了线程.那么map.size()是如何返回7和map.toString()返回8个实体的呢?

亲切的问候,
暴君

Mar*_*nik 8

通过同时改变映射,您已经破坏了它的内部不变量,并且您正在观察未指定和不可预测的行为,这是预期的结果.