Home > Ing. Software, Librerías/Frameworks, Testing > Is your code thread safe?

Is your code thread safe?

The last weeks I started to considerate about concurrency testing. I wrote an utility that tries to test if your code is thread safe or not.

When you repeat an experiment many times, the result tends to be the expected

This means that if you throw a die one time, we can not know what result is going to happen, but if we do it thousands of times, we will know that each result is going to happens 1/6 of the times.

In less words, lets repeat this many times at the same time and then check if it is fine or not. The problem here is, how to do it at the same time?.

The utility has 2 classes, ConcurrenceHelper and Task. Task is an interface that you need to implement to provide ConcurrenceHelper the job to do. ConcurrenceHelper will trigger all the tasks “at the same time”.

This is the interface:

public interface Task {

	void execute();
	
}

And this class will trigger all the tasks in different threads. Onces all the threads have executed the tasks, the main thread will leave the method (it means that this method is synchronous).

import java.util.concurrent.CountDownLatch;

public class ConcurrenceHelper {

	public void triggerTasks(final int nThreadsPerTask, final Task ... tasks) throws InterruptedException{
		final CountDownLatch waitForThreadsEnd = new CountDownLatch(nThreadsPerTask*tasks.length);
		final CountDownLatch waitToStart = new CountDownLatch(nThreadsPerTask*tasks.length);
		for(final Task task : tasks){
			for(int i=0;i<nThreadsPerTask;i++){
				final String THREAD_NAME = task+"-"+i;
				new Thread(new Runnable() {
					@Override
					public void run() {
						try {
							waitToStart.countDown();
							// Threads are waiting until countDown=nThreadsPerTask*tasks.length
							waitToStart.await();
							task.execute();
						} catch (InterruptedException e) {
							throw new RuntimeException(THREAD_NAME+" can not wait any more o_O", e);
						}finally{
                        	waitForThreadsEnd.countDown();
                        }
						
					}
				}, THREAD_NAME).start();
			}
		}
		// The main thread is waiting until countDown=nThreadsPerTask*tasks.length
		waitForThreadsEnd.await();
		// At this point all threads have executed the task
	}
	
}

And now lets do some testing:


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

import java.util.List;
import java.util.Vector;

import org.junit.Test;

public class SamplesTest {

	private final ConcurrenceHelper concurrence = new ConcurrenceHelper();
	private final int CONCURRENCE_TASKS = 10000;
	
	@Test
	public void vectorIsThreadSafe() throws InterruptedException{
		final List<Long> list = new Vector<>();
		concurrence.triggerTasks(CONCURRENCE_TASKS, new Task() {
			@Override
			public void execute() {
				list.add(System.currentTimeMillis());
			}
		});
		System.out.println("Value "+list.size());
		assertEquals(CONCURRENCE_TASKS, list.size());
	}
	
	@Test
	public void notThreadSafeClass() throws InterruptedException{
		final NotThreadSafeClass obj = new NotThreadSafeClass();
		concurrence.triggerTasks(CONCURRENCE_TASKS, new Task() {	
			@Override
			public void execute() {
				obj.i++;
			}
		});
		System.out.println("Value "+obj.i);
		assertNotEquals(CONCURRENCE_TASKS, obj.i);
	}
	
	private class NotThreadSafeClass{
		protected int i;
	}
	
}

We are testing one class that we know that is thread safe (Vector) and other one that is not thread safe (NotThreadSafeClass). It is easier to test that one class is thread safe than checking that is not thread safe. The test vectorIsThreadSafe() will be successfull the 100% of the times, but notThreadSafeClass() will not be successfull the 100%. For that reason, to prevent you to have randomly testing errors, make the testing oriented to check that is thread safe (by the way, is what we really want to test).

To prevent concurrency problems, try to make the classes as much inmutables as possible.

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: