Thursday, May 21, 2015

Synchronizing Java Method In A Cluster

In a multi-threaded environment, sometimes we have to write a method with a requirement that, at any point of time only one thread can execute the method. And we can achieve this easily with the java synchronized keyword. Declaring a java method as synchronized we can ensure that at any point of time only one thread in the JVM can execute the method. So its very simple to make a method synchronized in a JVM.

@Component
class MyClass{
  public synchronized void doSomething(){
      // do something
  }
}

The above strategy will work fine when your method is on a single JVM. What will happen if your method is executable on multiple JVMs ?  For example your method is a part of application deployed into multiple servers in your environment. So the above strategy of synchronizing your method will not work in a clustered environment. Because synchronized keyword can ensure synchronization only on single JVM. There are different ways to solve the problem, one of them is by using Hazelcast. In this example I am using maven, spring and Hazelcast to demonstrate the solution.


Step:1 Add Hazelcast Dependency


Add Hazelcast dependency to your pom or manually add the jar if it not a maven project.

<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast</artifactId>
    <version>3.2</version>
</dependency>


Step:2 Create a Hazelcast Instance During Application Startup


Create a Hazelcast object during application startup. Here I am using spring, so I will create Hazelcast object using spring bean , which will be instantiated when the spring context will be loaded. You can create the java object manually if you are not using spring.

<bean id="hazelcast" 
      class="com.hazelcast.core.Hazelcast" 
      factory-method="newHazelcastInstance"
   <constructor-arg>
      <bean class="com.hazelcast.config.Config">
        <property name="groupConfig">
          <bean class="com.hazelcast.config.GroupConfig">
            <property name="name" value="dev-cluster"/>
            <property name="password" value="secret"/>
          </bean>
        </property>
        <property name="networkConfig">
          <bean class="com.hazelcast.config.NetworkConfig">
            <property name="port" value="5555"/>
            <property name="join">
              <bean class="com.hazelcast.config.JoinConfig">
                <property name="tcpIpConfig">
                  <bean class="com.hazelcast.config.TcpIpConfig">
                    <property name="enabled" value="true"/>
                    <property name="members" value="hostname1,hostname2"/>
                  </bean>
                </property>
                <property name="multicastConfig">
                  <bean class="com.hazelcast.config.MulticastConfig">
                    <property name="enabled" value="false"/>
                  </bean>
                </property>
              </bean>
            </property>
          </bean>
        </property>
      </bean>
   </constructor-arg>
</bean>

Important Configuration Values :

dev-cluster : 
It is to give a name to the cluster.
secret : 
It is to give a password for the cluster members.
5555 : 
Port on which cluster members can talk to each other
hostname1, hostname2 : 
IP Address or Host Name of the members of the cluster separated by comma

Step:3 Hazelcast Object Should Be Accessible From Your Component


Create a new property in your class to hold this Hazelcast instance object and set it's value when you instantiate that class. Since I am using spring, I will set it in my class by autowiring. 

@Component
class MyClass{
  @Autowired
  Hazelcast hazelcast;
  public synchronized void doSomething(){
      // do something
  }
}

Step:4 Use Hazelcast Instance In Your Method To Make It Synchronized


Now I will change my method a little bit using Hazelcast to make it synchronized in a cluster. Now no need to use the synchronized keyword, so I am removing it from method signature. Add wrap your existing code as below. 

@Component
class MyClass{ 
  @Autowired
  Hazelcast hazelcast;
  public void doSomething(){
      ILock lock = hazelcast.getLock("mykey");
      try{
         lock.lock();
         // do something
      } catch (Exception e ) {
         // handle it in your own way
      } finally(){
         lock.unlock();
      }
  }
}

ILock lock = hazelcast.getLock("mykey");
This is to get the cluster level lock object with the name "mykey" and if no lock with such name exists in the cluster then it will first create and then return the lock. One lock can be created with a name.

lock.lock();
This is to acquire the cluster level lock. If a lock is acquired by any thread in the cluster, then no other thread can't acquire it, all others will go to waiting state. In a thread it can be acquires  only when it is not acquired. So at any point of time only one thread in the cluster can acquire the lock. 

NB :
To ensure threads will not go to wiating state for ever, you can pass the timeout value as parameter to the method, so that if a thread can not acquire the lock within that time period, this method can throw exception.

lock.unlock();
This is to release the lock acquired before, so that other threads in the cluster can acquire it.

So you are done.  This is how, you can very easily synchronize a java method in a cluster. Hazelcast can be used for more than this, it is just a very simple use of Hazelcast.

Happy Clustering !!!

Wednesday, May 20, 2015

Understanding Cloning in Java : Swallow vs Deep


Cloning is to create a copy of an object. And both original and cloned object should hold same values in their object graph. This article is to about how cloning works in java and different types of cloning.

Must implement Clonable Interface

Object class has a method called clone() to enable cloning of any object in Java. A class should implement Clonable interface to successfully invoke clone method of its object. If a class does not implement Clonable interface, then invoking clone() method on its object will throw CloneNotSupportedException.

Example :
class Example1{
....
}
class Example2 implements Clonable{
....
}
// Throw CloneNotSupportedException
Example1 example1Clone = (Example1)new Example1().clone();   
// Clone Successfully
Example2 example2Clone = (Example2)new Example2().clone();

Always Create A New Instance

When you call clone method of any Clonable object then it  create a new instance. So original object and cloned object are always 2 different instances.

Example :
class Example implements Cloneable{
...
}
// Create an object
Example original = new Example();
// Clone an object
Example cloned = (Example)original.clone();
// 2 different instances 
object == cloned; // false

Swallow Cloning

By default java does swallow cloning for you. In swallow cloning, a new instance of the original object is created but the instance variables in both original object and cloned object refer to same instances.

Example :

class MyObject {
   int value;
   public MyObject(int value){
       this.value = value;
   }
   public int getValue(){
     this.value;
   }
}

class Example implements Cloneable{
   MyObject myObject;
   public Example(MyObject myObject){
       this.myObject = myObject;
   }
   public MyObject getMyObject(){
       return this.myObject;
   }
}

// Create Original Object
Example original = new Example(new MyObject(55));
// Create Cloned Object
Example cloned = (Example)original.clone();
// Instance variable of both refering to same object instance 
original.getMyObject() == cloned.getMyObject(); // true
// So the values in both should be same
original.getMyObject().getvalue()== cloned.getMyObject().getvalue();

Deep Cloning

In deep cloning original object's  object graph and cloned object's object graph should not share any common object, they should have their own copy in their object graph. To achieve deep cloning,you need to override the default clone method. To ensure implementing deep cloning , create the whole object graph by copying the values manually inside clone method.

Example :

class MyObject {
   int value;
   public MyObject(int value){
       this.value = value;
   }
   public int getValue(){
     this.value;
   }
}

class Example implements Cloneable {
   MyObject myObject;
   public Example(MyObject myObject){
       this.myObject = myObject;
   }
   public MyObject getMyObject(){
       return this.myObject;
   }
   @Override
   public Object clone()throws CloneNotSupportedException {
      MyObject myObject = new MyObject(this.myObject.getValue());
      return new Example(myObject);
   }
}

// Create Original Object
Example original = new Example(new MyObject(55));
// Create Cloned Object
Example cloned = (Example)original.clone();
// Instance variable of both refering to different object instances 
original.getMyObject() == cloned.getMyObject(); // false
// But the values in both should be same
original.getMyObject().getvalue()== cloned.getMyObject().getvalue();


Sometimes it is very difficult to implement clone method for deep cloning, specially when of very complex or big object graph involved. So in such cases safe way is to serialize the object, then deserialize. This ensures everything is a brand new reference.  Example Here