Monday, January 31, 2005

Variation on Double-checked locking


The problems with the double checked locking idom are documented here.



I propose the following as a variation when it can't be refactored in other ways. I still need to investigate if this variation actually protects from pipeline optimization.




public class HeavySingleton {

private static HeavySingleton instance;
private static Object lock = new Object();

/**
* Only permit instance access via factory method(s).
*/
private HeavySingleton() {
}

public static HeavySingleton instance() {
if (instance == null) {
synchronized (lock) {
// Does this protect from parallelism?
HeavySingleton temp = instance;
if (temp == null) {
temp = new HeavySingleton();
instance = temp;
}
}
}
return instance;
}
}



Other options:



  • if a class is always going to be used, then lazy instantiation is really pointless


  • create a factory class with synchronized methods


  • if this is an early optimization, and premature optimization is the root of all evil...



willCode4Beer

permalink
Links to this post
0 comments

Wednesday, January 26, 2005

Java Coding Practices

I can't believe that I haven't found this site before.
Its a good collection of standard practices. Think 'Effective Java' extended.

Paul

permalink
Links to this post
1 comments

Friday, January 21, 2005

Service Locator Pattern + Dependency Inversion Principle

The Service Locator Pattern helps to encourage modular application design. The Dependency Inversion Principle states that modules should depend upon abstractions instead of other modules. Using JNDI we can merge the design pattern and development practice.

So, in places where a module needs to use the services of another module, create an interface that defines the methods required. Next add a final static String to the interface defining a JNDI name for the interface and ensure the interface extends Serializable. Next create a factory class to return an instance of the interface from a JNDI lookup using the name specified in the interface. An alternative, to eliminate duplicate code in the facotry classes, is to create a single factory class that provide a method taking the string as a parameter.
ex:
IMyDataSource = (IMyDataSource) Locator.instance().getService(IMyDataSource.JNDI_NAME);

The initialization routine of the application can bind the JNDI names to the actual implementors of the interfaces. Now, whenever a service is required of a module, the component requiring it will retrieve the actual objects performing the service from the factory classes. I prefer to place all of these interfaces and their factory classes into a separate package from any implementation or application code. This package then acts as a directory of the services available for the application.

What benefits are gained with this methodology? First, a very clean design with no cross dependencies between modules. This means the application should have a lower cost of maintenance. Also, each component can be tested in isolation. If using JUnit, the JNDI names can be bound to mock objects to enhance testing capabilities. Services can be swapped out while the application is running, not just config time. Processor instensive services can be placed on remote machines allowing for transparent clustering. If the JNDI lookups become a performance issue, changing the factory class to simply return instances is a trivial change.

Following is an example implementation of a Locator class:


import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
* @author Paul E. Davis
*/
public class Locator {

private static Locator instance;
protected static Object lock = new Object();

private Locator() {
}

public static Locator instance() {
if (instance == null) {
synchronized (lock) {
if (instance == null) {
instance = new Locator();
}
}
}
return instance;
}

public Object getService(String name) {
return lookupService(name);
}

private Object lookupService(String name) {
Object out = null;
try {
Context ctx = new InitialContext();
out = ctx.lookup(name);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return out;
}
}

willCode4Beer

permalink
Links to this post
0 comments