go to  ForumEasy.com   
JavaPro
Home » Archive » Message


[Email To Friend][View in Live Context][prev topic « prev post | next post » next topic]
  What we can learn from Singleton Pattern -- Potential Concurrent Access Issues.
 
Subject: What we can learn from Singleton Pattern -- Potential Concurrent Access Issues.
Author: Alex_Raj
In response to: What we can learn from Singleton Pattern -- There is always an alternative way.
Posted on: 12/05/2013 11:57:14 PM


Let's consider a real scenario: a sequence number or auto increment number is globally needed for all records or change events pushing into database. The number must be unique across all application environment. For this case, a sequence generator in singleton pattern is a perfect solution.

/**
 * A Real Example: Sequence Generator -- (not right)
 */
public class SequenceGenerator 
{
    /* static field to ensure only one copy */
    private static final SequenceGenerator INSTANCE = new SequenceGenerator();

    private long sequenceNumber;

    /* private constructor to prevent it from being instantiated from outside */
    private SequenceGenerator() {
        sequenceNumber = 0L; // or loading from persistence
    }

    /* public static method to ensure global point of access */
    public static SequenceGenerator getInstance() {
        return INSTANCE;
    }

    public long nextNumber() {
        sequenceNumber++;
        return sequenceNumber;
    }
}


As singleton suggests only one instance and global accessibility, there is a very high chance that the instance methods are accessed concurrently due to the shared nature of the instance. Here in this example, the operation sequenceNumber++; is not atomic and hence the method nextNumber() must be mutual exclusively blocked.

/**
 * A Real Example: Sequence Generator -- synchronized version
 */
public class SequenceGenerator 
{
    /* static field to ensure only one copy */
    private static final SequenceGenerator INSTANCE = new SequenceGenerator();

    private long sequenceNumber;

    /* private constructor to prevent it from being instantiated from outside */
    private SequenceGenerator() {
        sequenceNumber = 0L; // or loading from persistence
    }

    /* public static method to ensure global point of access */
    public static SequenceGenerator getInstance() {
        return INSTANCE;
    }

    public synchronized long nextNumber() {
        sequenceNumber++;
        return sequenceNumber;
    }
}


OR:

/**
 * A Real Example: Sequence Generator -- atomic version
 */
import java.util.concurrent.atomic.AtomicLong;
public class SequenceGenerator 
{
    /* static field to ensure only one copy */
    private static final SequenceGenerator INSTANCE = new SequenceGenerator();

    private AtomicLong atomicSequenceNumber;

    /* private constructor to prevent it from being instantiated from outside */
    private SequenceGenerator() {
        atomicSequenceNumber = new AtomicLong(0L); // or loading from persistence
    }

    /* public static method to ensure global point of access */
    public static SequenceGenerator getInstance() {
        return INSTANCE;
    }

    public long nextNumber() {
        return atomicSequenceNumber.incrementAndGet();
    }
}



 

> On 12/05/2013 11:49:13 PM Alex_Raj wrote:

Early Instantiation Version:

If the program will always need an instance, or if the cost of creating the instance is not too large in terms of time/resources, the programmer can switch to eager initialization, which always creates an instance:
/**
 * Early instantiation version - no synchronization is needed
 */
public class Singleton 
{
    /* static field to ensure only one copy */
    private static final Singleton INSTANCE = new Singleton();

    /* private constructor to prevent it from being instantiated from outside */
    private Singleton() {
    }

    /* public static method to ensure global point of access */
    public static Singleton getInstance() {
        return INSTANCE;
    }

    public void sayHello() {
        System.out.println("Hello");
    }
}


This version has a number of advantages:
  • The instance is not constructed until the class is used.
  • There is no need to synchronize the getInstance() method, meaning all threads will see the same instance and no (expensive) locking is required.
  • The final keyword means that the instance cannot be redefined, ensuring that one (and only one) instance ever exists.


    Lazy Inner Static Class Version:

    /**
     * Lazy inner static class version - no synchronization is needed
     */
    public class Singleton 
    {
        /* static class to ensure only one copy & lazy load as is needed*/
        private static class SingletonHolder {
            public static final Singleton INSTANCE = new Singleton();
        }
    
        /* private constructor to prevent it from being instantiated from outside */
        private Singleton() {
        }
    
        /* public static method to ensure global point of access */
        public static Singleton getInstance() {
            return SingletonHolder.INSTANCE;
        }
    
        public void sayHello() {
            System.out.println("Hello");
        }
    }
    


    This version has a number of advantages:
  • The instance is not constructed until getInstance() method is used.
  • There is no need to synchronize the getInstance() method, meaning all threads will see the same instance and no (expensive) locking is required.
  • The final keyword means that the instance cannot be redefined, ensuring that one (and only one) instance ever exists.




    References:

  •  


     
    Powered by ForumEasy © 2002-2022, All Rights Reserved. | Privacy Policy | Terms of Use
     
    Get your own forum today. It's easy and free.