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".
Not sure if the presentation is correct
by
Matej Tymes
For example a method can return a MUTABLE subclass of this "IMMUTABLE" class and the whole concept of immutability is lost.
Re: Not sure if the presentation is correct
by
Matej Tymes
public class MyBestAddressBook extends BestAddressBook {
private List<String> names;
public MyBestAddressBook(List<String> names) {
super(names);
this.names = new ArrayList<String>(names);
}
public List<String> getNames() {
return names;
}
public void addName(String name) {
names.add(name);
}
}
And then test it:
public class TestImmutabilityKiller {
public static BestAddressBook getAddressBook(List<String> bookNames) {
return new MyBestAddressBook(bookNames);
}
public static void main(String[] args) {
BestAddressBook addressBook = getAddressBook(Arrays.asList("Men at Arms", "Guards! Guards!"));
System.out.println("before modification:");
System.out.println(addressBook.getNames());
if(addressBook instanceof MyBestAddressBook) {
((MyBestAddressBook)addressBook).addName("Faust - Eric");
}
System.out.println("after modification:");
System.out.println(addressBook.getNames());
}
}
After you test it the result will be:
before modification:
[Men at Arms, Guards! Guards!]
after modification:
[Men at Arms, Guards! Guards!, Faust - Eric]
As you can see I have been able to add a new book name into the "IMMUTABLE" BestAddressBook class
Re: Not sure if the presentation is correct
by
Matej Tymes
a. mark the class BestAddressBook as final or
b. mark the method BestAddressBook.getNames() as final or
c. mark the constructor of class BestAddressBook as private and use static factory method or inner static builder class for new instance creation or
d. maybe there is also some different solution
Re: Not sure if the presentation is correct
by
Adel Manatad
Why would you want to repeat the already stable base class' List<String> member "names" in a subclass? Your intention is just too wicked, or you might just lack OOP design skills. As you can see, to create your argument you are forced to use the "instanceof" operator in an if statement, which usually shows as a sign of a smelly code.
If you would really need to subclass BestAddressBook to implement an "is a" relationship, then you don't need to define "names" list again on the subclass. Making so will defeat the very essence of "structural inheritance".</string>
Re: Not sure if the presentation is correct
by
Adel Manatad
Re: Not sure if the presentation is correct
by
Matej Tymes
Re: Not sure if the presentation is correct
by
Jules Jacobs
Immutablity Puzzle #2 error
by
Mike S
Re: Not sure if the presentation is correct
by
Mario Gleichmann
String[] friends = new String[]{ "Helen", "John", "Karen", "Peter" };
AdressBook adressBook = new AdressBook( friends );
fiends[1] = "Jonas";
Puzzle 3 is also mutable!
by
Mario Gleichmann
List<String> friends = new ArrayList<String>();
friends.add( "Helen" );
...
BetterAdressBook adressBook = new BetterAdressBook( friends );
friends.remove( 1 );
friends.add( 1, "Jonas" );</string></string>
Re: Puzzle 3 is also mutable!
by
Arturs Licis
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.
Re: Not sure if the presentation is correct
by
Rameshkumar Ramasamy
Re: Not sure if the presentation is correct
by
Frederick Polgardy
Educational Content
Building Hypermedia APIs with HTML
Jon Moore Jun 19, 2013
Deleting Code at Nokia
Tom Coupland Jun 19, 2013
Intro to CLP with core.logic
Ryan Senior Jun 18, 2013
Spock: A Highly Logical Way To Test
Howard Lewis Ship Jun 18, 2013
Java Garbage Collection Distilled
Martin Thompson Jun 17, 2013




Hello stranger!
You need to Register an InfoQ account or Login to post comments. But there's so much more behind being registered.Get the most out of the InfoQ experience.
Tell us what you think