2

From what I read, there is no "good" general solution to unit-test thread-safety. But I would like a good solution for a specific problem.

Let's consider this (dummy) dynamic list implementation. The add method is clearly not thread-safe. Since it is pretty obvious to make it thread-safe (let us consider we will not implement any remove method and keep it dummy), how would one unit-test the piece of code to show it is actually not thread-safe and show that the thread-safety fix actually works (or seems to work)?

public class ArrayList {

    private int capacity = 2;
    private Object[] content = new Object[capacity];
    private int size;

    public void add(Object object) {
        if (size == capacity) {
            ensureCapacity();
        }
        content[size++] = object;
    }

    public Object get(int index) {
        if (index >= size) {
            throw new IndexOutOfBoundsException();
        }
        return content[index];
    }

    private void ensureCapacity() {
        int extendedCapacity = capacity * 2;
        Object[] extended = new Object[extendedCapacity];

        System.arraycopy(content, 0, extended, 0, size);

        this.capacity = extendedCapacity;
        this.content = extended;
    }
}
AST
  • 211
  • 6
  • 18
Alban Dericbourg
  • 1,616
  • 2
  • 16
  • 39
  • 1
    You can't guarantee what order two threads would run through the `add` method or when either might be pre-empted - therefore you cannot write a consistent test – Nick Holt Aug 10 '15 at 14:19
  • Possible duplicate of http://stackoverflow.com/questions/12159 – Moby Disk Aug 10 '15 at 14:35
  • I don't consider it as a duplicate since I'm trying to get an answer around an example. But it there's actually no way to properly unit-test thread-safety in any case... it becomes de facto a duplicate. – Alban Dericbourg Aug 10 '15 at 14:40
  • The only way to _prove_ that multi-threaded code works as intended is to test every possible serialization of the "operations" (i.e., the shared memory reads and writes) that are executed by the various threads. That can be practical for small algorithms and small numbers of threads, but as far as I know, it's still a research topic: I have not heard of any tool that helps either with enumerating or with forcing different serializations of Java byte codes. – Solomon Slow Aug 10 '15 at 16:16
  • You would use a library like Awaitility for simulating specific ordering, and then also have threads thrash it for good measure. – Ben Manes Aug 10 '15 at 16:38

3 Answers3

2

you can give a try to some utilities like jcstress http://openjdk.java.net/projects/code-tools/jcstress/ or thread-weaver https://github.com/google/thread-weaver who will instrument your byte code and generate stress tests for you implementation.

twillouer
  • 1,149
  • 9
  • 14
1

You face the following two problems during testing

  1. The program may behave different depending on the hardware or jvm used.
  2. Bugs happens only in very specific thread and timing constellations.

To solve Point 2 you can use http://openjdk.java.net/projects/code-tools/jcstress/. It basically tests a list of assertions under load. I think this might be the correct solution for your use case, developing a new concurrent collection.

To solve Point 1, you can use http://vmlens.com. It is a tool which checks if all accessed fields in a program run can be ordered according to the java memory model. This make sure that the order of the program does not depend on the hardware or jvm.

So if your use case is to develop a new concurrent collection, I would check it with http://vmlens.com and then test it with http://openjdk.java.net/projects/code-tools/jcstress/ on a machine with many cores.

(I am biased so, I develop http://vmlens.com)

Thomas Krieger
  • 1,607
  • 11
  • 12
0

You can try to simulate a race condition by putting sleeps in the threads that test the method. But obviously it won't be a 100% reliable test. My advice is that you just make the code thread-safe whenever you know in advance that it will be accessed simultaneously. Otherwise you're opening up room for our beloved synchronization bugs...

Dimitar
  • 134
  • 1
  • 6