Thread Safety

Leave a comment

June 29, 2011 by huionn

Today I was coding a small piece of code that may be accessed by multiple threads concurrently. I wondered whether my code is thread safe. So I referred to Java Concurrency In Practice.

A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.

Based on the book’s definition, concept of correctness is the key to thread safety. But what is correctness?

Correctness means that a class conforms to its specification.

After reading a few related chapters, I think incorrectness can means stale value, lost update and invariants violation. After I digested the concept, I wrote the code below based on my understanding. (In my code, the new value of list is independent of its previous contents)

public class BadThreadSafe {
	private List<Object> list = Collections.emptyList();
	
	public void setList(List<Object> list) {
		if (list == null) {
			throw new IllegalArgumentException("list cannot be null");
		}
		this.list = Collections.unmodifiableList(list);
	}

	/**
	 * read-only list
	 * @return
	 */
	public List<Object> getList() {
		return list;
	}
	
	public void safeProcess() {
		/*
		for ( Iterator<Object> iter = list.iterator(); iter.hasNext(); ) {
	        	Object o = iter.next();
	       		System.out.println(o);
	    	}
	    	*/
		// shorthand for above
		for (Object o : list) {
			System.out.println(o);
		}
	}

	public void unsafeProcess() {
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
	}
}

Explanation:

Although states of list are immutable, list itself is mutable. So, by right, this class is not thread safe.

However in my opinion, without unsafeProcess(), this class is thread safe (although it’s fragile: broken if old list is used to construct new list by calling code).

In Java, it is guaranteed that the assignment of the reference is atomic. In addition, stale value and lost update do no harm in this example. Once the iterator has been assigned, the change of list reference will not affect the iterator.

On the contrary, in unsafeProcess(), the reference of list may change between list.size() and list.get(i). In this scenario, the invariant of the class has been broken.

How to fix it? Simple…

List local = list;

for (int i = 0; i < local.size(); i++) { System.out.println(local.get(i)); }

Local variable is thread safe because of stack confinement.

Advertisements

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: