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

Bookmarks

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

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

  • Not sure if the presentation is correct

    by Matej Tymes,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    From my point of view non of this classes can't provide you immutablity guaranty if they can be subclassed.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    to prove this statement just think that I will create this class extension:



    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    but otherwise, its quite nice article :)

  • Re: Not sure if the presentation is correct

    by Matej Tymes,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    to resolve this you must:



      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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Matej's explanation of the effects of marking a class and methods as final is absolutely correct, but his "context" for making his argument (albeit just to play the devil's advocate) is just plain ugly and wrong design decision!

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Your example was not able to change the BestAddressBooks' names field. What it changed was the subclass' names field. It just showed that BestAddressBook is really immutable indeed. :)

  • Re: Not sure if the presentation is correct

    by Matej Tymes,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Yes, but, when you for example create a service that is doing something with the BestAddressBook you expect that the BestAdressBook is imutable and everything is fine. Fine till somebody in the future (and it is not you) decides that for his subproject he would like to extend the class with sorting functionality. He can't modify your BestAddressBook and he can't modify your cool service. So he decides that the easiest thing is to extend the BestAddressBook (in the way I have described) and as he assumes everything will work just fine. But it won't be as you have allowed him to destroy it (because you were expecting that everybody will create an execelent code). Of course you could check if the BestAddressBook you have received isn't a subclass, but from my point of view this is really not the best aproach.

  • Re: Not sure if the presentation is correct

    by Jules Jacobs,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    The answer to the second immutability puzzle is wrong. You're defining getNames(int n) but calling getNames(). The second class *is* immutable.

  • Immutablity Puzzle #2 error

    by Mike S,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    In "Immutablity Puzzle #2" class AddressBook does not expose names array reference via getter so it is actually "immutable" from this article's point of view.

  • Re: Not sure if the presentation is correct

    by Mario Gleichmann,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Although AdressBook does in fact not return the whole names array, the class is still mutable, in that the creator of an instance of an AdressBook still holds a direct reference to the names array and therefore could alter it afterwards:

    String[] friends = new String[]{ "Helen", "John", "Karen", "Peter" };

    AdressBook adressBook = new AdressBook( friends );

    fiends[1] = "Jonas";

  • Puzzle 3 is also mutable!

    by Mario Gleichmann,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    BetterAdressBook is also mutable since the creator of an instance may also keeps holding a direct reference to the List which he passed to the constructor:


    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Actually this is reviewed in Puzzle #4:


    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I am not able to Compile #Puzzle4, using Eclipse 3.3 + JDK 1.6.0_12. Error is "Immutable cannot be resolved to a type". May I know which jar file I'm missing, that need to be included in the classpath, to get it compiled.

  • Re: Not sure if the presentation is correct

    by Frederick Polgardy,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I believe it was intended to be a marker annotation that you could create on your own to denote immutability in your system. @Immutable isn't a Java API.

  • Re: Not sure if the presentation is correct

    by Chung Juan,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    It is true that you modifiy names, but this is the field in your class MyBestAddressBook, it is your duty to control whether this filed is immutable. if you try to modify the field names in the super class, an exception may be thrown!

  • Good "follow up question based" approach of the article is helpful for interview

    by sankalp suryawanshi,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    This article is quite helpful for preparing the topic for interviews. As it goes gradually to next step and discuss further details as it usually asked in tech interviews.
    Thanks and keep sharing.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT