I haven't been able to reproduce the failure, but here's a patch that I'm planning to commit, and that I expect to reduce the risk of this happening again.
Currently, the test has a race between two threads that perform the following steps:
T1_1: compile query
T1_2: start executing query
T1_3: lock row
T2_1: start new thread
T2_2: compile query
T2_3: start executing query
T2_4: lock row
The events T1_3 and T2_4 must happen no more than 2 seconds apart.
The patch makes sure that both of the two threads have completed the query compilation before the race starts. Since there are less steps to be done concurrently, and also the amount of work done concurrently is more evenly distributed, the chance of a big time difference in the last step should be smaller.
It does this by splitting up Statement.executeQuery() into prepareStatement() + executeQuery() and introducing a barrier before the executeQuery() calls to make sure they start at the same time.
I factored out the already existing Barrier classes from IndexSplitDeadlockTest and DeadlockDetectionTest for this purpose (since we cannot use java.util.concurrent.CyclicBarrier as long as we support platforms less capable than Java 5).