Unexpected Multithreading in Java

Multiple processor and multicore computing platforms are becoming very common and most programmers are aware that special Java programming techniques are required in these environments. A popular technique is to ensure that your code always executes in a single thread. It’s a reasonable strategy but it’s very easy to unintentionally violate that constraint.

Consider this scenario. Let’s say you have created an InvoiceProcessor class that maintains a count of how many invoices have been processed. The class uses this count for logging purposes. Let’s also say the server is implemented using a Spring IOC container and a single-threaded JMS message listener container. The architect designed it this way to eliminate the need for the programmers to worry about concurrency issues. Or so he thought.

Your invoice process might look something like the following…

public class InvoiceProcessor {
    private int invoiceCount;

    public void process(Invoice invoice) {
       // ...
       invoiceCount++;
    }

    // ...

    public int getInvoiceCount() {
       return invoiceCount;
    }
}

One day a developer decides that it would be cool to use JMX to monitor the invoice count. With Spring, they just add some JMX annotations to the InvoiceProcessor and them make some simple modifications to their Spring configuration to detect their annotated MBeans. They fire up JConsole and are are delighted to see their invoice count displayed there. They can even see a graph of the invoice counts over time. Very cool. However, their delight soon fades. While testing, they notice the counts in JConsole don’t match the number of invoices in their test case. What happened? They’ve been bitten by unexpected multithreading.

Remote JMX access has created multithread access to the InvoiceProcessor. There are no memory barriers around access to the count field so there’s no way to know if the value returned by the JMX remoting thread is anywhere close to the value seen in the thread that processes invoices. Making the count field volatile is a potential solution in this scenario.

Although this example is hypothetical, I’ve actually seen a bug like this in previous versions of Hibernate’s JMX support. In general, be aware that remote JMX access will require any instrumented classes to be thread safe.

Of course, there are other ways to be bitten by unexpected multithreading. For example, you might use the InvoiceProcessor in a Swing GUI and display the count in a monitoring panel. Now the count field is being accessed from both the AWT event dispatching thread and the request processing thread. Or you might decide to schedule a Quartz job to reset the count every day at midnight. This is easily done in the Spring configuration file, but once again, your code now must now be thread safe. Other possible sources of unexpected multithreading are Java shutdown hooks or object finalizers since they run in their own threads. If you know of other common sources of unexpected multithreading, share them in the comments.

Add a Comment

Your email address will not be published. Required fields are marked *