简体   繁体   English

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

[英]Static java HashMap concurrency in unit test issue

I have a class (lets call it XClass) which has a method (lets call it xMethod), that I am testing. 我有一个类(我们称它为XClass),其中有一个我正在测试的方法(我们称其为xMethod)。 It also contains a: 它还包含一个:

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

In my setup method of the unit test I have: 在单元测试的设置方法中,我有:

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

In the test method I create couple of (in my case 8) threads. 在测试方法中,我创建了两个(在我的情况下为8个)线程。 Their run method invokes xClass.xMethod. 他们的运行方法调用xClass.xMethod。 This method changes the static map variable. 此方法更改静态映射变量。 The method xMethod, is supposed to invoke map.containsKey() map.get() and map.put() 8 times. 方法xMethod应该调用8次map.containsKey()map.get()和map.put()。 It doesn't do any remove. 它不会做任何删除。 This method also doesn't create any new threads, so the map shouldn't be changed once the thread is finished with the xMethod. 此方法也不会创建任何新线程,因此一旦线程使用xMethod完成,就不应更改映射。 I wait for all of the threads to finish (either normally or by an exception). 我等待所有线程完成(正常或异常)。 Than I check the map 比我查看地图

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

It fails here with the message: 它在此处失败,并显示以下消息:

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

I solved the problem by using a ConcurrentHashMap, but I am still puzzled with the issue. 我通过使用ConcurrentHashMap解决了问题,但我仍然对该问题感到困惑。 How is it possible after all 8 threads finish, for the map to behave weird (size() returns 7 but toString() prints 8 entities)? 在所有8个线程完成之后,如何使映射表现得很奇怪(size()返回7而toString()打印8个实体)呢? I would have understood if there were 7 entites and the size() method gave 7, but there are 8 entities in the map. 我应该知道是否有7个实体,并且size()方法给出了7个,但是地图中有8个实体。 How is this possible?! 这怎么可能?!

Btw, I checked the termination of the threads in couple of ways: 顺便说一句,我以几种方式检查了线程的终止:
1. with a check for the Thread.State.TERMINATED. 1.检查Thread.State.TERMINATED。
2. I printed a simple message before the method return, printed a simple message after the threads were done (and checked there were no exceptions thrown. The 8 messages are always written before the 9th (in the test after threads "finished"). 2.我在方法返回之前打印了一条简单消息,在线程完成之后打印了一条简单消息(并检查是否抛出异常。这8条消息始终在第9条之前写入(在测试中,线程“结束”之后)。
3. Even done a simple thread which in the run method contained the following logic: 3.甚至执行了一个简单的线程,该线程在run方法中包含以下逻辑:

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

Than I would only loop indefinitely until all of the threads had their finished == true. 然后,我将无限期地循环直到所有线程完成== true。

All of these imply that the threads are finished before I continue with asserting and checking the map. 所有这些都意味着在继续声明和检查映射之前,线程已完成。 So how, again, is it possible for the map.size() to return 7 and the map.toString() to return 8 entities?! 那么,再次,map.size()如何返回7以及map.toString()返回8个实体又如何呢?

Kind Regards, 亲切的问候,
despot 暴君

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

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

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