繁体   English   中英

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

[英]Static java HashMap concurrency in unit test issue

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

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

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

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

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

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

它在此处失败,并显示以下消息:

java.lang.AssertionError:映射:{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个实体,并且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;
        }

然后,我将无限期地循环直到所有线程完成== true。

所有这些都意味着在继续声明和检查映射之前,线程已完成。 那么,再次,map.size()如何返回7以及map.toString()返回8个实体又如何呢?

亲切的问候,
暴君

通过同时对地图进行变异,您已经破坏了其内部不变性,并且观察到未指定且不可预测的行为,这是预期的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM