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

时间:2013-01-16 14:55:55

标签: java unit-testing concurrency hashmap

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

private static Map<String, String> map = new HashMap<String, String>();

在单元测试的设置方法中,我有:

ReflectionTestUtils.setField(xClass, "map", map, null);

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

int mapSize = map.size();
assertEquals("map:" + map, 8, mapSize);

这里的消息失败了:

  

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

我通过使用ConcurrentHashMap解决了这个问题,但我仍然对这个问题感到困惑。 在所有8个线程完成之后怎么可能,因为地图表现得很奇怪(size()返回7但toString()打印8个实体)?我会理解是否有7个entites和大小()方法给出了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;
        }

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

所有这些都意味着在继续断言和检查地图之前线程已经完成。那么map.size()有可能返回7而map.toString()返回8个实体吗?

亲切的问候,

1 个答案:

答案 0 :(得分:8)

通过同时改变地图,你已经破坏了它的内部不变量,你正在观察未指定和不可预测的行为,这是预期的结果。