Java race condition provocation

I need to write a unit test that provokes a race condition, so I can check if I can solve the problem later. The problem is that the race condition is very rare, maybe because my computer has only two cores.

The code looks something like this:

class MyDateTime { String getColonTime() { // datetime is some kind of lazy caching variable declared somewhere(does not matter) if (datetime == null) { initDateTime(); //Uses lazy to initlialize variable, takes some time } // Colon time stores hh:mm as string if (datetime.colonTime == null) { StringBuilder sb = new StringBuilder(); //Now do some steps to build the hh:mm string //... //set colon time datetime.colonTime = sb.toString(); } return datetime.colonTime; } } 

Explanation: initDateTime assigns a new instance of dateTime, so datetime.colonTime is null after that (since we want to initialize it lazy, as I said). Now, if Thread A enters the method, then the scheduler stops it just before initDateTime () is run. Thread B is now runst getColonTime (), sees that datetime is still null and initializes it. datetime.colonTime is null, so the second if block is executed, and datetime.colonTime is StringBuilder. If then the scheduler stops the thread between this line and the return statement and resumes thread A, the following happens: When A was stopped just before the initDateTime call, A now calls initDateTime (), which will look like reset the datetime object, again setting datetime.colonTime to null . Then thread A will go into the second if block, but the scheduler will abort A before datetime.colonTime = sb.toString (); called. As a conclusion, dateTime.colonTime is still null. Now the scheduler resumes B, and the method returns null.

I tried to provoke a race condition by pointing multiple threads calling getColonTime () on one (final) instance of MyDateTime, but it only fails in some unusually rare cases :( Any hints on how to write JUnit "test"?

+6
source share
3 answers

You can look at Thread Weaver , or there may be other frameworks for testing multi-threaded code. I have not used it, but the User Guide looks as if it is intended for this type of testing.

+4
source

As you say, race conditions are extremely difficult to reproduce sequentially. However, the law of averages is on your side. If you create a test that you expect to receive, perhaps once a hundred times, and then do it a thousand times, you will probably understand the error quite consistently in your old code. Thus, in accordance with the principles of TDD, you should start with the code as it was before, come up with a test, iterate enough time to work consistently against the old code, and then switch to the new code and make sure that it does not work.

+7
source

I know this post is pretty old, but I came across a similar situation. What I mean is to approve the terms of the race with spins.

In your case, I would do something like

  class MyDateTime { String getColonTime() throws InterruptedException{ if (datetime == null) { Thread.sleep(new Random().nextInt(100); //Wait to enhance the chances that multiple threads enter here and reset colonTime. initDateTime(); } Thread.sleep(new Random().nextInt(100); //Wait to enhance the chances that colonTime stays null for a while. if (datetime.colonTime == null) { StringBuilder sb = new StringBuilder(); datetime.colonTime = sb.toString(); } Thread.sleep(new Random().nextInt(100); //Wait to favour reset of colonTime by another thread in the meantime. return datetime.colonTime; } } 

But it is clear that it is getting rather dirty. I would like some way to get the planner to explore all the paths given by some of the โ€œbreak pointsโ€.

Since the post is a bit outdated, I was wondering if you found good ways to check the race conditions in Java. Any advice to share?

thanks

0
source

Source: https://habr.com/ru/post/897473/


All Articles