BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Concurrency and Immutability

Concurrency and Immutability

Concurrency is increasingly a very important aspect of modern applications. As we scale to higher levels of traffic and demand, there is a greater need for multiple concurrent threads of execution. As such, the role of objects managed by the dependency injector is extremely important. Singletons are a particularly significant example of this need.

In a large web application handling several hundreds of a requests per minute, a poorly designed singleton can be a serious bottleneck. It introduces ceilings on concurrent performance, and can even render the application unscalable under certain conditions.

Poorly concurrent behavior is also more common than you might think. And since its effects are only highlighted during performance testing, it can be difficult to identify and mitigate. So it is quite relevant for us to study the effects of concurrency on singletons.

Mutability is an essential variable in this problem. Some pitfalls are contained within the idea of immutability, too, so let's explore exactly what it means to be immutable. To change things up, we'll look at this as a series of puzzles.

Immutablity Puzzle #1

Is the following class, Book, immutable?

public class Book {
	private String title;
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
}

Answer #1

This one's easy: no. The value of its title field can be changed arbitrarily by calling setTitle() so it is clearly not immutable. We can make Book immutable by declaring title final as shown below:

public class ImmutableBook {
	private final String title;
	public ImmutableBook(String title) {
		this.title = title;
	}
	public String getTitle() {
		return title;
	}
}

Once set in the constructor, the value of title cannot change.

Immutablity Puzzle #2

Is the following class, AddressBook, immutable?

public class AddressBook {
	private final String[] names;
	public AddressBook(String[] names) {
		this.names = names;
	}
	public String[] getNames() {
		return names;
	}
}

Answer #2

The value of the names field is set once in the constructor and is declared final. So AddressBook should be immutable, right? No! In fact, the subtle point is that since names is an array, only the reference to it is immutable by declaring it final. The following code is perfectly legal and can potentially lead to a world of hurt where multiple threads are concerned:

public class AddressBookMutator {
	private final AddressBook book;

	@Inject
	public AddressBookMutator(AddressBook book) {
		this.book = book;
	}

	public void mutate() {
		String[] names = book.getNames();


		for (int i = 0; i < names.length; i++)
			names[i] = "Censored!"

		for (int i = 0; i < names.length; i++)
			System.out.println(book.getNames()[i]);
}
} 

Method mutate() destructively updates the array, even though field names is unchangeable. If you run the program it prints out "Censored!" for every name in the book. The only real solution to this problem is not to use arrays, or to use them very sparingly behind well understood safeguards and documentation. Prefer library collections (such as those found in java.util) classes where possible as these can be guarded by unmodifiable wrappers. See puzzle #3 for an illustration of using java.util.List instead of an array.

Immutablity Puzzle #3

Is the following class, BetterAddressBook, immutable?

 public class BetterAddressBook {
	private final List<String> names;

 	public BetterAddressBook(List<String> names) {
		this.names = Collections.unmodifiableList(names);
	 }
 	public List<String> getNames() {
		return names;
 }
}

Answer #3

Thankfully, yes, BetterAddressBook is immutable. The wrapper provided by the Collections library ensures that no updates can be made to the list once it has been set. The following code, though it compiles, results in an exception at runtime:

BetterAddressBook book = new BetterAddressBook(Arrays.asList("Landau", "Weinberg", "Hawking"));
book.getNames().add(0, "Montana");

Immutablity Puzzle #4

This is a variant on puzzle #3. Take the same BetterAddressBook class we saw earlier. Is it at all possible to construct it in such a way that I can mutate it? You are not allowed to change the code of BetterAddressBook.

The answer is quite simple, if a bit confounding:

List<String> physicists = new ArrayList<String>();
physicists.addAll(Arrays.asList("Landau", "Weinberg", "Hawking"));
BetterAddressBook book = new BetterAddressBook(physicists);
physicists.add("Einstein");

Now an iteration through BetterAddressBook's list of names:

for (String name : book.getNames())
System.out.println(name);

So, really, we must revise what we said in the answer to puzzle #3. BetterAddressBook is only immutable if its dependency list is not leaked anywhere else. Better yet, we can rewrite a completely safe version of it by copying the list at the time of its construction:

@Immutable
public class BestAddressBook {
	private final List<String> names;
	public BestAddressBook(List<String> names) {
		this.names = Collections.unmodifiableList(new ArrayList<String>
(names));
	}
	public List<String> getNames() {
		return names;
	}
}

Now you are free to leak and mutate the original list:

List<String> physicists = new ArrayList<String>();
physicists.addAll(Arrays.asList("Landau", "Weinberg", "Hawking"));


BetterAddressBook book = new BetterAddressBook(physicists);


physicists.clear();
physicists.add("Darwin");
physicists.add("Wallace");
physicists.add("Dawkins");

for (String name : book.getNames())
	System.out.println(name);

...and BestAddressBook remains unaffected:

Landau
Weinberg
Hawking

While it may not always be necessary to take such a cautious approach, it is advisable to copy argument lists if you are at all unsure about them escaping into other uses subsequent to construction of the immutable object.

Immutablity Puzzle #5

Is the following class, Library, immutable? (Recall Book from puzzle #1)

public class Library {
	private final List<Book> books;

	public Library(List<Book> books) {
		this.books = Collections.unmodifiableList(new ArrayList<Book>(books));
	}
	public List<Book> getBooks() {
		return books;
	}
}

Answer #5

Library depends on a list of Books, but it takes care to wrap the incoming list in an unmodifiable wrapper and copies it prior to doing so. Of course, its only field is final too. Everything looks right--or does it? Actually, it turns out that Library is mutable! While the collection of books is unchangable, there is still the Book object itself. Which, as you may recall from the first puzzle, allows its title to be set:

Book book = new Book();
book.setTitle("Dependency Injection")
Library library = new Library(Arrays.asList(book));
library.getBooks().get(0).setTitle("The Tempest"); //mutates Library

The golden rule with immutability and object graphs is that every dependency of an object must also be immutable. In the case of BestAddressBook, we got lucky, since Strings in Java are already immutable. Take care to ensure that every dependency you have is safely immutable before declaring an object as such. The @Immutable annotation seen in " Immutablity Puzzle #4" helps a great deal in conveying and documenting this intent.


This article is excerpted from the upcoming title Dependency Injection by Dhanji R. Prasanna and published by Manning Publications. It explores the concept of immutability in a series of five puzzles. For the table of contents, the Author Forum, and other resources, go to http://manning.com/prasanna/.

InfoQ readers will receive a 25% discount when ordering via manning.com. Use discount code, "infoq25".

Rate this Article

Adoption
Style

BT