Already we have a nice article about about problems with double check locking. we will see two nice quick workarounds and its pros and cons.Double-checked locking: Clever, but broken and Double-Checked Locking is Broken.
before getting into solution, classic singleton uses the following signature for get instance:
class ReduceNto1{
int max=0;
private static ReduceNto1 r1=new ReduceNto1();
public static ReduceNto1 getInstance(){
return r1;
}
private ReduceNto1(){}
public synchronized void setMax(int n){
System.out.println("***"+n);
if(n>max){
max=n;
}
}
public int getMax(){
return max;
}
}
class MaxFinder implements Runnable {
int max=Integer.MIN_VALUE;
int arr[];
public MaxFinder(int arr[]){
this.arr=arr;
}
public void run() {
findMax();
System.out.println(max);
System.out.println(Thread.currentThread().getName()+"****setting max from this thread to reduce*****"+max);
ReduceNto1.getInstance().setMax(max);
}
public void findMax(){
for(int i=0;i<arr.length;i++){
if(arr[i]>max)
max=arr[i];
}
}
public int getMax(){
return max;
}
}
public class ConcurrentReadingFromNarray {
public static void main(String[] args) {
// TODO Auto-generated method stub
int arr1[]={1,2,3,4,5,49,7,49,9,10};
int arr2[]={11,12,13,14,15,16,17,18,19,20};
Thread t1=new Thread(new MaxFinder(arr1));
Thread t2=new Thread(new MaxFinder(arr2));
t1.start();
t2.start();
try{
t1.join();
t2.join();
}catch(Exception e){}
System.out.println("Max No is : "+ReduceNto1.getInstance().getMax());
}
}
before getting into solution, classic singleton uses the following signature for get instance:
public static Resource getResource() {
if (resource == null)
resource = new Resource();
return resource;
}
if (resource == null)
resource = new Resource();
return resource;
}
so the above code will only create the new resource object if no instance of resource is found. This mechanism is called lazy loading more preciously need based loading we only load resources if and only if it is required. Benefit associated with this approach is performance improvement, if resource creation is a heavy process and we do not want it to be carried when class is loading t then this classic approach does make sense.
public static synchronized Resource getResource() {
if (resource == null)
resource = new Resource();
return resource;
}
if (resource == null)
resource = new Resource();
return resource;
}
we just make that getInstance method synchronized and rest remain same as classic singleton, so object is created only if it is required. How ever there is a downside to it, synchronization is expensive, it takes more time to run method with synchronized keyword than ordinary method. Since getInstance is synchronized every call to this method will be more expensive.
Another work around is to use a static initializer to create singleton object as soon as class is loaded by class loader;
class Singleton{
private static Singletonr singleton=new Singleton();
public static Singleton getInstance(){
return singleton;
}
return singleton;
}
}
This is guaranteed to be thread safe. The downside of creating singleton like this we are creating it eagerly so singleton is always created even if it is never needed.
So both the approach has its strengths and downsides associated with it, we can select our approach based on application's need .
an example with second approach:
class ReduceNto1{
int max=0;
private static ReduceNto1 r1=new ReduceNto1();
public static ReduceNto1 getInstance(){
return r1;
}
private ReduceNto1(){}
public synchronized void setMax(int n){
System.out.println("***"+n);
if(n>max){
max=n;
}
}
public int getMax(){
return max;
}
}
class MaxFinder implements Runnable {
int max=Integer.MIN_VALUE;
int arr[];
public MaxFinder(int arr[]){
this.arr=arr;
}
public void run() {
findMax();
System.out.println(max);
System.out.println(Thread.currentThread().getName()+"****setting max from this thread to reduce*****"+max);
ReduceNto1.getInstance().setMax(max);
}
public void findMax(){
for(int i=0;i<arr.length;i++){
if(arr[i]>max)
max=arr[i];
}
}
public int getMax(){
return max;
}
}
public class ConcurrentReadingFromNarray {
public static void main(String[] args) {
// TODO Auto-generated method stub
int arr1[]={1,2,3,4,5,49,7,49,9,10};
int arr2[]={11,12,13,14,15,16,17,18,19,20};
Thread t1=new Thread(new MaxFinder(arr1));
Thread t2=new Thread(new MaxFinder(arr2));
t1.start();
t2.start();
try{
t1.join();
t2.join();
}catch(Exception e){}
System.out.println("Max No is : "+ReduceNto1.getInstance().getMax());
}
}
Out Put:
20
49
Thread-0****setting max from this thread to reduce*****49
Thread-1****setting max from this thread to reduce*****20
***20
***49
Max No is : 49
49
Thread-0****setting max from this thread to reduce*****49
Thread-1****setting max from this thread to reduce*****20
***20
***49
Max No is : 49
Comments
Post a Comment