tempus-fugit

Java micro-library for writing & testing concurrent code

Avoid JMock Finaliser Problems

The default threading policy for a JMock Mockery warns if the mockery is being used by multiple threads. The SingleThreadedPolicy will output the following.

2012-05-31 07:35:35 ERROR Finalizer [Console$Logger] - the Mockery is not thread-safe: use a Synchroniser to ensure thread safety

If you really need multi-threaded access to the mockery, it’s a straight forward fix to swap the policy out. As in the log line above though, sometimes the JVM’s finaliser thread sticks it’s oar in and confuses the SingleThreadedPolicy.

To get rid of this, you can set a custom threading policy that performs the same check as the default, just not when the finaliser thread is involved.

1
2
3
private final Mockery context = new Mockery() {{
    setThreadingPolicy(new SingleThreadedPolicyAvoidingFinaliseProblems());
}};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static class SingleThreadedPolicyAvoidingFinaliseProblems extends SingleThreadedPolicy {
    @Override
    public Invokable synchroniseAccessTo(Invokable unsynchronizedInvocation) {
        Invokable synchronizedInvocation = super.synchroniseAccessTo(unsynchronizedInvocation);
        return new InvokeBasedOnCurrentThreadBeingTheFinalizerThread(unsynchronizedInvocation, synchronizedInvocation);
    }
}

private static class InvokeBasedOnCurrentThreadBeingTheFinalizerThread implements Invokable {

    private final Invokable whenOnFinalizerThread;
    private final Invokable whenNotFinalizerThread;

    public InvokeBasedOnCurrentThreadBeingTheFinalizerThread(Invokable whenOnFinalizerThread, Invokable whenNotFinalizerThread) {
        this.whenOnFinalizerThread = whenOnFinalizerThread;
        this.whenNotFinalizerThread = whenNotFinalizerThread;
    }

    @Override
    public Object invoke(Invocation invocation) throws Throwable {
        if (currentThreadIs("Finalizer"))
            return whenOnFinalizerThread.invoke(invocation);
        return whenNotFinalizerThread.invoke(invocation);
    }

    private static boolean currentThreadIs(String name) {
        return Thread.currentThread().getName().equalsIgnoreCase(name);
    }
}

See the bug report JMOCK-256 for more details.

Over to you...