Thread Jiggling

Overview

Thread jiggler is a simple testing framework for exercising code to find threading problems. It works by modifying classes bytecode at runtime to insert Thread.yield() calls between instructions – “jiggling” the threads. This greatly increases the likelihood of discovering threading issues, and does it without you needing to change your production code.

Background

I was recently researching how to test multithreaded code for threading issues, and found out about a tool from IBM called ConTest, but couldn’t find any code I could use myself. So naturally, I thought I’d spike my own.

Consider this canonical simple, but thread unsafe class:

private int count = 0 ;

    public void count() {
        count++;
    }

The count method’s byte code is:

DUP
GETFIELD asm/Foo.counter : I
ICONST_1
IADD
PUTFIELD asm/Foo.counter : I

This provides several places where there could be a context switch, which means that count my be increased, but not stored as expected. Let consider a quick unit test:

Counter counter = new BadCounter();
    int n = 1000;

    @Test
    public void singleThreadedTest() throws Exception {

        for (int i = 0; i < n; i++) {
            counter.count();
        }

        assertEquals(n, counter.getCount());
    }
    ...

This test runs in a single thread, and passes. Lets try and run this on two threads and see if it fails.

public void threadedTest() throws Exception {

        final CompletionService<Void> service = new ExecutorCompletionService<Void>(Executors.newFixedThreadPool(2));

        for (int i = 0; i < n; i++) {
            service.submit(new Callable<Void>() {
                @Override
                public Void call() {
                    counter.count();
                    return null;
                }
            });
        }

        for (int i = 0; i < n; ++i) {
            service.take().get();
        }

        assertEquals(n, counter.getCount());
     }

This also passes. On my computer I can increase n to 100,000 before it starts to fail consistently.

Expected :1000000
Actual   :999661

Just 0.04% of the tests had a problem. What have we learned? We’ve learned a simple way to run a multithreaded test, but we’ve learned that, because we can’t control when threads do their work, it’s a bit trial and error.

Thread Jiggling

So one problem exercising code to find threading defects is that you can’t control when threads will yield. However, we can re-write the bytecode to insert Thread.yield() into the bytecode between instructions. In the above example we can get the code to produce more issues by changing the bytecode:

DUP
GETFIELD asm/Foo.counter : I
INVOKESTATIC java/lang/Thread.yield ()V
ICONST_1
IADD
PUTFIELD asm/Foo.counter : I

Using ASM, we can create a rewriter to insert these invocations. The JigglingClassLoader re-writes classes on the fly, adding these calls. From this we can create a JUnit runner to run use the new class loader for the test.

@Jiggle("threadjiggler.test.*")
public class BadCounterTest {
    ...
}

Now running the test:

Expected :1000000
Actual   :836403

The number of test where we see the threading problem jump to 16%. We’ve done this with out any recompilation of the code, or impacting on other unit tests running in the same JVM.

Exercise for the Reader

SimpleDateFormat is a well know, non-thread safe class in Java. Write a test that jiggles the class. Why is it not thread-safe? How would you rewrite it so that it was thread safe? How can you do so without using a ThreadLocal, locks or synchronisation?

Source Code

The code for this can be found on Github.

Further Reading

I’ve written a post on testing threaded code for correctnes. You may also wish to read more generally:

 

Reference: Thread Jiggling from our JCG partner Alex Collins at the Alex Collins ‘s blog blog.
Related Whitepaper:

Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code

Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!

To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.

Get it Now!  

Leave a Reply


1 + = three



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books