Thread Safety Strategies

4 minute read

Published:

Recently I was asked to look into a production issue in a payment application. After going through hours of debugging we could zero into the cause of the problem. Not surprisingly it was due concurrent requests from different users arriving at our server in same instant. Thankfully the fix was quick in this case, but this let me to think how important it is for todays developers to know about Thread Safety and how their code will behave in case of multi-threaded environment

Why should we worry about Thread Safe Classes

Where threads were more esoteric, thread safety was considered as an advanced topic; now mainstream developers must be aware of thread-safety issues Brian Goetz

Invariably the code you are writing will most likely be executed in a multi-core environment and you can no longer assume that it is only one thread.

A piece of code that is not thread safe might appear to work, passing its tests and performing well for years, but it is still broken and may fail at any moment

One of the critical reason to be aware of Thread Safety is there are no definative tools to test for Thread Safety. It is vey difficult to write JUnit for concurrent execution of piece of code

Attemps to Test for Thread Safety In this article I am refering two ways which we can write some JUnits to test for concurrency

Weaver

Weaver is a framework for writing multi-threaded Unit Tests in Java. Let’s see an example of the same.

The below class is an example of Thread Un-Safe class.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class EmployeeList {

	private List employee = Collections.synchronizedList(new ArrayList());

    public boolean putIfAbsent(String employeeName) {
        boolean absent = false;

        absent = !employee.contains(employeeName);
        if (absent) {
        employee.add(employeeName);
        }

        return absent;
    }

    public int size() {
        return employee.size();
    }
}

With some bad timing we can have two threads finding list does not contain the employee name and so both the threads would add the element in the list Below is a JUnit using Weaver to test it

import org.junit.Test;

import com.google.testing.threadtester.AnnotatedTestRunner;
import com.google.testing.threadtester.ThreadedAfter;
import com.google.testing.threadtester.ThreadedBefore;
import com.google.testing.threadtester.ThreadedMain;
import com.google.testing.threadtester.ThreadedSecondary;

import static org.junit.Assert.*;

public class EmployeeListMultiThreadedTest {

	EmployeeList list;

	@Test
	public void testPutIfAbsent() {
		AnnotatedTestRunner runner = new AnnotatedTestRunner();
		// Run all Weaver tests in this class, using EmployeeList as the Class Under
		// Test.
		runner.runTests(this.getClass(), EmployeeList.class);
	}


	@ThreadedBefore
	public void before() {
		list = new EmployeeList();
	}

	@ThreadedMain
	public void mainThread() {
		list.putIfAbsent("Dhananjay");
	}

	@ThreadedSecondary
	public void secondThread() {
		list.putIfAbsent("Dhananjay");
	}

	@ThreadedAfter
	public void after() {
		assertEquals(1, list.size());
	}

}

If you run the above Unit test, it would fail with an Error as size would be 2.

Explanation of how Weaver works in the above test is given here Weaver Explained.

I found this to be very useful to quickly write JUnits to verify how our classes would behave in case of multi-threaded environment

vmlens

vmlens enables you to unit test your multithreaded java code. The following exampl shows how you can use vmlens in your JUnits

public class Counter {
    private int count = 0;

	public void addOne() {
		count++;
	}

	public int getCount() {
		return count;
	}

}

This is classic Thread Unsafe code. Below is JUnit which we can use to test the same

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.anarsoft.vmlens.concurrent.junit.ConcurrentTestRunner;

@RunWith(ConcurrentTestRunner.class)
public class CounterTest {

    private Counter counter = new Counter();

    @Test
    public void addOne() {
        counter.addOne();
    }

    @After
    public void testCount() {

        assertEquals("4 Threads running addOne in parallel should lead to 4" , 4 , counter.getCount());

    }

}

By using the RunWith annotation the JUnit test is run by a special ConcurrentTestRunner. This test runner runs the method annotated with “Test” parallel in 4 threads. After that it executes the methods marked with the annotation After” in the main thread. If you run the test case very often, you will sometimes see an assertion failed exception.

Guidelines for Thread Safety

3 common concurrency mechanisms generally used in combination with each other to safely access data from multiple threads

  1. Dynamic Exclusion Through Implicit Locks
  2. Structural Exclusion Through Confinement
  3. Immutability

I will try to explain more on these guidelines in following articles.

Leave a Comment

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

Loading...