Monday, May 30, 2016

ConcurrentHashMap vs Hashtable vs Synchronized Map


v ConcurrentHashMap performs better than earlier two because it only locks a portion of Map, instead of whole Map, which is the case with Hashtable and synchronized Map.

v CHM allows concurred read operations and same time, maintains integrity by synchronizing write operations. 

v ConcurrentHashMap is best suited when you have multiple readers and few writers. 

v During update operation, ConcurrentHashMap only lock a portion of Map instead of whole Map.
"Concurrency level", allows ConcurrentHashMap to partition Map.

v ConcurrentHashMap partitions Map into different parts based on concurrency level and locking only a portion of Map during updates. Default concurrency level is 16, and accordingly Map is divided into 16 part and each part is governed with different lock. This means, 16 thread can operate on Map simultaneously, until they are operating on different part of Map. This makes ConcurrentHashMap high performance despite keeping thread-safety intact. 

v Another important point to remember is iteration over CHM, Iterator returned by keySet of ConcurrentHashMap are weekly consistent and they only reflect state of ConcurrentHashMap and certain point and may not reflect any recent change. Iterator of ConcurrentHashMap's keySet area also fail-safe and doesn’t throw ConcurrentModificationExceptoin.

v Default concurrency level is 16 and can be changed.

v ConcurrentHashMap doesn't allow null as key or value.

v ConcurrentHashMap provides putIfAbsent(key, value) which does same thing but atomically and thus eliminates below race condition.

synchronized(map){
  if (map.get(key) == null){
      return map.put(key, value);
  } else{
      return map.get(key);
  }
}

HashMap
Collections.SynchronizedMap
ConcurrentHashMap
No Synchronization
Use very simple synchronization, which means that only one thread can access the map at the same time.
Allow parallel read access by multiple threads without synchronization and, more importantly, provides an Iterator that requires no synchronization and even allows the Map to be modified during interation
Null key-value pair allowed
No Null Key-value pair
No Null Key-value pair
No Lock Mechanism . HashTable locks the object
Locks the whole map
Locks the segment out of 16 segments. Locks bucket only
Not thread-Safe
Thread-Safe
Thread-Safe
Fail-fast Iterator
Fail-fast Iterator
Fail-safe Iterator

Why Concurrent HashMap doesn’t allow null key ?

The main reason that nulls aren't allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) because there will be ambiguities that may be just barely tolerable in non-concurrent maps can't be accommodated.

The main one is that if map.get(key) returns null, you can't detect whether the key explicitly maps to null vs the key isn't mapped.

if (key == null || value == null) throw new NullPointerException();
public class ConcurrentHashMapDemo {

     public static void main(String[] args) {
           ConcurrentHashMap<String, String> chm= new ConcurrentHashMap<>();
           chm.put(null,"Paras");
           System.out.println(chm.get(null));
     }
}

Output:

Exception in thread "main" java.lang.NullPointerException
at java.util.concurrent.ConcurrentHashMap.putVal(Unknown Source)
at java.util.concurrent.ConcurrentHashMap.put(Unknown Source)
at com.javadsalgo.ConcurrentHashMapDemo.main(ConcurrentHashMapDemo.java:9)

In a non-concurrent map, you can check this via map.contains(key), but in a concurrent one, the map might have changed between calls.

The code is like this :

    
if (map.containsKey(k)) {
     return map.get(k);
else {
     throw new KeyNotPresentException();
}

It might be possible that key k might be deleted in between the get(k) and containsKey(k) calls.
As a result, the code will return null as opposed to KeyNotPresentException (Expected Result if key is not present).


The Null key and value allowed in HashMap because there is no Concurrent access.

Saturday, May 28, 2016

Tricky equals() in Java

Behavior of equal() in Java with different Objects

Integer class

Integer i2 = new Integer(100);
Integer i3 = 100;
System.out.println(i2.equals(i3));

public boolean equals(Object paramObject) {
            if (paramObject instanceof Integer)
                  return (this.value == ((Integer) paramObject).intValue());
            return false;
      }

All wrapper classes overriding equals() and thus checking actual value instead of addresses.

String class

 public boolean equals(Object paramObject) {
              if (this == paramObject)
                     return true;
              if (paramObject instanceof String) {
                     String str = (String) paramObject;
                     int i = this.value.length;
                     if (i == str.value.length) {
                           char[] arrayOfChar1 = this.value;
                           char[] arrayOfChar2 = str.value;
                           for (int j = 0; i-- != 0; ++j)
                                  if (arrayOfChar1[j] != arrayOfChar2[j])
                                         return false;
                           return true;
                     }
              }
              return false;
       }

Object Class

public boolean equals(Object paramObject) {
              return (this == paramObject);
       }


public class EqualsMethod {

     public static void main(String[] args) {
           Integer i1 = new Integer(200);
           Integer i2 = 200;
           Integer i3 = new Integer(200);
           System.out.println("--equals() for Integer Object--");
           // Checking address and not values
           System.out.println(i1 == i2);
           // equals() Checks values thus result is true
           System.out.println(i1.equals(i2));
           System.out.println(i1.equals(i3));

           System.out.println("--equals() for Build In Object--");

           Employeee e1 = new Employeee("Paras", "Rohtak");
           Employeee e2 = new Employeee("Paras", "Rohtak");
           System.out.println(e1.equals(e2));
           System.out.println(e1 == e2);
          
           System.out.println("--equals() for String Object--");
           String s1= new String("Paras");
           String s2= new String("Paras");
           String s3="Paras";
           // Check values and not address
           System.out.println(s1.equals(s3));
           System.out.println(s1.equals(s2));
           System.out.println(s1==s2);
     }
}

class Employeee {
     String name;
     String address;

     Employeee(String name, String address) {
           this.name = name;
           this.address = address;
     }
}



Output:
--equals() for Integer Object--
false
true
true
--equals() for Build In Object--
false
false
366712642
--equals() for String Object--
true
true
false