Fail safe and fail fast in iterators. A.K.A Concurrency handling in collections

One day I have asked this question is in interview. “what is different between fail safe and fail fast in iterators?” fail fast mean fail with exception fail safe mean fail without exception. I knew that candidate just lied to sake of giving answer.

Java collection framework is quite popular framework as well as required framework on java programming. however most of new developers following wrong practice when they use collection framework. specially with concurrent access environment.

in iterators there are two type of implementations.

  1. fail fast
  2. fail safe

both of these has its own unique qualities. so we really cant advice which one to use as its highly depend on your requirement. therefore having correct understanding about those two is really important.

Fail fast

most of developers think concurrent Exception can happen only on multi threaded environment. but that is not true. that can happen in single thread environment too. fail fast means if your collection modified in any way except using own method of iterator, iteration cycle will fail with ConcurrentModificationException. that means if you implemented in this way it is guaranteed that collection remain unchanged until it finished the iterations. in other words collection will not modified during iterations. but this cannot category as thread safe. because it allow to modify the collection. however iteration will fail and stop.

also keep a note that it will throw ConcurrentModificationException ONLY if iterator had to access the collection after modified. in other words if you modify collection after last iteration it wont throw any exceptions. also iterator it self not a collection. here collection means underlying collection which iterator linked.

lets consider an example

package com.krishantha.sample.java;

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;

public class FailFast {
	public static void main(final String[] args) {
		final List<String> city = new ArrayList<>();
		city.add("Colombo");
		city.add("Galle");
		city.add("Mathara");
		city.add("Gampaha");
		city.add("Kadawatha");

		System.out.println("============= Before ==========");
		Iterator<String> cityIterator = city.iterator();
		while (cityIterator.hasNext()) {

			System.out.println(cityIterator.next());

		}
		System.out.println("============= Try ==========");
		cityIterator = city.iterator();
		int i = 1;
		try {
			while (cityIterator.hasNext()) {
				System.out.println(cityIterator.next());
				if (i == 2) {
					city.remove(i - 1);
				}
				System.out.println("size of collection is " + city.size());
				i++;
			}
		} catch (final ConcurrentModificationException ce) {
			ce.printStackTrace();
		}
		System.out.println("============= After ==========");
		cityIterator = city.iterator();
		while (cityIterator.hasNext()) {

			System.out.println(cityIterator.next());

		}
	}
}

this is the outout

============= Before ==========
Colombo
Galle
Mathara
Gampaha
Kadawatha
============= Try ==========
Colombo
size of collection is 5
Galle
size of collection is 4
java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
	at java.util.ArrayList$Itr.next(ArrayList.java:851)
	at com.krishantha.sample.java.FailFast.main(FailFast.java:29)
============= After ==========
Colombo
Mathara
Gampaha
Kadawatha

you can see here exception caused when line number 29. means when trying to access the collection after modification. so its allowed to modify. when someone asked “what is fail fast in term of iterations” if you answered as “it not allowed to modify collection…” its wrong. it will allowed to modify but it will break when trying access next time. (you can see “Galle” is removed) also it will not will break if you modified via own “remove” method

use own remove method.

when you use iterator own remove method to remove you can be safe.

package com.krishantha.sample.java;

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;

public class FailFast {
	public static void main(final String[] args) {
		final List<String>city = new ArrayList<>();
		city.add("Colombo");
		city.add("Galle");
		city.add("Mathara");
		city.add("Gampaha");
		city.add("Kadawatha");

		System.out.println("============= Before ==========");
		Iterator<String>cityIterator = city.iterator();
		while (cityIterator.hasNext()) {

			System.out.println(cityIterator.next());

		}
		System.out.println("============= Try ==========");
		cityIterator = city.iterator();
		int i = 1;
		try {
			while (cityIterator.hasNext()) {
				System.out.println(cityIterator.next());
				if (i == 2) {
					cityIterator.remove();
				}
				System.out.println("size of collection is " + city.size());
				i++;
			}
		} catch (final ConcurrentModificationException ce) {
			ce.printStackTrace();
		}
		System.out.println("============= After ==========");
		cityIterator = city.iterator();
		while (cityIterator.hasNext()) {

			System.out.println(cityIterator.next());

		}
	}
}

here output as follows

============= Before ==========
Colombo
Galle
Mathara
Gampaha
Kadawatha
============= Try ==========
Colombo
size of collection is 5
Galle
size of collection is 4
Mathara
size of collection is 4
Gampaha
size of collection is 4
Kadawatha
size of collection is 4
============= After ==========
Colombo
Mathara
Gampaha
Kadawatha

you can see second element was removed from the list. (index start from 0 and out i start from 1) “Galle” was the current index when we call remove(). that means we have modified the collection with out breaking the program.

for each is safe?

some developers think that they can avoid this ConcurrentModificationException if they use for-each loop. but that is lie. for-each is just wrap for iterator. when you extract iterator and going through it little tedious task. underlying for each is running iterator. only thing is you don’t need to handle it manually.

lets prove it.

package com.krishantha.sample.java;

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;

public class FailFast {
	public static void main(final String[] args) {
		final List<String> city = new ArrayList<>();
		city.add("Colombo");
		city.add("Galle");
		city.add("Mathara");
		city.add("Gampaha");
		city.add("Kadawatha");

		System.out.println("============= Before ==========");

		for (String cityName : city) {
			System.out.println(cityName);
		}

		System.out.println("============= Try ==========");
		int i = 1;
		try {
			for (String cityName : city) {
				System.out.println(cityName);
				if (i == 2) {
					city.remove(city.size() - 1);
				}
				System.out.println("size of collection is " + city.size());
				i++;
			}

		} catch (final ConcurrentModificationException ce) {
			ce.printStackTrace();
		}
		System.out.println("============= After ==========");
		for (String cityName : city) {
			System.out.println(cityName);
		}
	}
}

output is

============= Before ==========
Colombo
Galle
Mathara
Gampaha
Kadawatha
============= Try ==========
Colombo
size of collection is 5
Galle
size of collection is 4
============= After ==========
java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
	at java.util.ArrayList$Itr.next(ArrayList.java:851)
	at com.krishantha.sample.java.FailFast.main(FailFast.java:25)
Colombo
Galle
Mathara
Gampaha

you can see it is same results. its breaking since we modified the collection.

This is very important before move in to next. ConcurrentModificationException is cannot guaranteed. so it should NOT be used to detect data structure modified or not. because it thrown when modification detected. not thrown. in simple word should write program to depend on this exception.

Fail-safe

this means it will not fail at all. oh!! so it is good. why we should write program in fail fast way while you have immunity with you?? but that is bad idea. fail fast is better than fail safe when it comes to larger collections. why?

fail safe is achieving its goad by simple concept. it take a copy of data structure before start iterate. its iterate through copy. not the original data structure. so when you modify your data structure iterator wont catch it. in other words updates to data structure will not effect immediately.

package com.krishantha.sample.java;

import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class FailFast {
	public static void main(final String[] args) {
		final Map<String, String> city = new ConcurrentHashMap<>();
		city.put("SL", "Kadawatha");
		city.put("IN", "Bangalore");
		city.put("US", "Durham");
		city.put("CH", "Macaw");
		city.put("SG", "Singapore");

		System.out.println("============= Before ==========");
		Iterator<String> cityIterator = city.values().iterator();
		while (cityIterator.hasNext()) {
			System.out.println(cityIterator.next());
		}

		System.out.println("============= Try ==========");
		cityIterator = city.values().iterator();
		int i = 1;
		try {
			while (cityIterator.hasNext()) {
				System.out.println(cityIterator.next());
				if (i == 2) {
					city.remove("IN");
				}
				System.out.println("size of collection is " + city.size());
				i++;
			}

		} catch (final ConcurrentModificationException ce) {
			ce.printStackTrace();
		}
		System.out.println("============= After ==========");
		cityIterator = city.values().iterator();
		while (cityIterator.hasNext()) {
			System.out.println(cityIterator.next());
		}
	}
}

output is

============= Before ==========
Singapore
Bangalore
Macaw
Kadawatha
Durham
============= Try ==========
Singapore
size of collection is 5
Bangalore
size of collection is 4
Macaw
size of collection is 4
Kadawatha
size of collection is 4
Durham
size of collection is 4
============= After ==========
Singapore
Macaw
Kadawatha
Durham

you can see here map has been modified its “try” section. that is why in “after” section “IN” value is missing. but it does not caused any exception.

As the feature is nice its comes with some draw backs. since it iteration is going through copy when you deal with large data set it can create memory over loading issues. also when consider large data sets it take times to reflect modifications to data set. that mean any modification done during iteration will reflect untill current iterations complete.

Little advance

since now you are clear with concept we can go little more advance. in fail safe “creating copy of internal data structure” is general explanation. there are implementations which follow different approach. as an example ConcurrentHashMap does not take copy. it keep lock. when read request comes it wait write request to completed. you can lean this by reading about ConcurrentHashMap documentation. point is however it implement it has weaknesses over fail fast.

Does it caused all modification of collection? No. consider below example. it is same as previous. but trying add to list instead of remove.

package com.krishantha.sample.java;

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;

public class FailFast {
	public static void main(final String[] args) {
		final List<String> city = new ArrayList<>();
		city.add("Colombo");
		city.add("Galle");
		city.add("Mathara");
		city.add("Gampaha");
		city.add("Kadawatha");

		System.out.println("============= Before ==========");
		Iterator<String> cityIterator = city.iterator();
		while (cityIterator.hasNext()) {
			System.out.println(cityIterator.next());
		}
		System.out.println("============= Try ==========");
		cityIterator = city.iterator();
		int i = 1;
		try {
			while (cityIterator.hasNext()) {
				System.out.println(cityIterator.next());
				if (i == 2) {
					city.add("Tangalle");
				}
				System.out.println("size of collection is " + city.size());
				i++;
			}
		} catch (final ConcurrentModificationException ce) {
			ce.printStackTrace();
		}
		System.out.println("============= After ==========");
		cityIterator = city.iterator();
		while (cityIterator.hasNext()) {

			System.out.println(cityIterator.next());

		}
	}
}

output is

============= Before ==========
Colombo
Galle
Mathara
Gampaha
Kadawatha
============= Try ==========
Colombo
size of collection is 5
Galle
size of collection is 6
java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
	at java.util.ArrayList$Itr.next(ArrayList.java:851)
	at com.krishantha.sample.java.FailFast.main(FailFast.java:27)
============= After ==========
Colombo
Galle
Mathara
Gampaha
Kadawatha
Tangalle

it also thrown exception as last time. now use set instead of add. change below code block

	if (i == 2) {
		city.add("Tangalle");
	}

in to

	if (i == 2) {
		city.set(0,"Tangalle");
	}

output is

============= Before ==========
Colombo
Galle
Mathara
Gampaha
Kadawatha
============= Try ==========
Colombo
size of collection is 5
Galle
size of collection is 5
Mathara
size of collection is 5
Gampaha
size of collection is 5
Kadawatha
size of collection is 5
============= After ==========
Tangalle
Galle
Mathara
Gampaha
Kadawatha

that mean list is updated without giving exception. so now you can fine tune your answer. exception throws only if structure modification caused to collection. not the value changes. above example value changed while keeping structure un change.

What to use?

How can I advice that? now you know theory. so its up to you to decide what to use.

 

 

 

Share this on your world...Share on Facebook
Facebook
Share on Google+
Google+
Tweet about this on Twitter
Twitter
Share on LinkedIn
Linkedin
Email this to someone
email
Print this page
Print

Leave a Reply