简体   繁体   中英

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. 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. Their run method invokes 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. 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. 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>

I solved the problem by using a ConcurrentHashMap, but I am still puzzled with the issue. How is it possible after all 8 threads finish, for the map to behave weird (size() returns 7 but toString() prints 8 entities)? I would have understood if there were 7 entites and the size() method gave 7, but there are 8 entities in the map. 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.
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").
3. Even done a simple thread which in the run method contained the following logic:

        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.

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?!

Kind Regards,
despot

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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