Multiton & Singleton

From J2EE Bloger http://j2eeblogger.blogspot.com/2007/10/singleton-vs-multiton-synchronization.html

1. Classic Java singleton synchronization problem

public class Singleton {
	private static Singleton instance;

	/** Prevents instantiating by other classes. */
	private Singleton(){}

	public static synchronized Singleton getInstance() {
		if (instance == null){
			instance = new Singleton();
		}
		
		return instance;
	}
}

The synchronized keyword on the getInstance() method is the evil. In a multi-thread environment, every thread will be blocked by each other when trying to grab the singleton instance. This is the classic java singleton synchronization problem.

 

 

2. The traditional solution using a static variable.

public class Singleton {
	/** Prevents instantiating by other classes. */
	private Singleton() {}
	
	private final static Singleton instance = new Singleton();
	
	public static Singleton getInstance() {
		return instance;
	}
}

The singleton instance is initialized during the class loading time. No synchronization is necessary on the getInstance level.

 

 

3. The classic synchronized multiton.

public class Multiton {
	private static final HashMap<Object, Multiton> instances = new HashMap<Object, Multiton>();

	private Multiton(){}

	public static Multiton getInstance(Object key){
		synchronized (instances) {
		// Our "per key" singleton
		Multiton instance;
		if ((instance = instances.get(key)) == null) {
			// Lazily create instance and add it to the map
			instance = new Multiton();
			instances.put(key, instance);
		}
		
		return instance;
		}
	}
}

The Multiton pattern begins with the concept of the Singleton pattern and expands it into an object pool of keys to objects. Instead of having a single instance per runtime, the Multiton pattern ensures a single instance per key. It simplifies retrieval of shared objects in an application.

As we noticed from the above scriptlet, the access to the getInstance() method is synchronized to ensure the uniqueness of instance per key. This, again, is a performance bottleneck in multi-thread environment. The traditional 'static' solution for Singleton pattern can't be used here since the keys are passed into the Multiton on-the-fly. We have no way to predict how many keys will be passed into the Multiton during the runtime.
 
 
4. The double-check locing solution
public class Multiton {
	private static final HashMap<Object, Multiton> instances = new HashMap<Object, Multiton>();

	public static Multiton getInstance(Object key) {
		// Our "per key" singleton
		Multiton instance;
	 
		if ((instance = instances.get(key)) == null) {
			synchronized(instances) {
				if ((instance = instances.get(key)) == null) {
					instance = new Multiton();
					instances.put(key, instance);
				}
			}
		}
		
		return instance;
	}
}

Yes the double-checked locking does not work for Singleton (http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html), but it does work for our Multiton pattern. Reason? We have our intermediate HashMap object sits in between. Actually we can use the HashMap to solve the Singleton double-checked locking problem as well, if we don't already have the more elegant solution using a static variable.

 

 

5. An alternative solution: Using the Java 5 ConcurrentMap

public class Multiton {
	private static final ConcurrentMap<Object, Multiton> instances = new ConcurrentHashMap<Object, Multiton>();

	public static Multiton getInstance(Object key) {
		// Our "per key" singleton
		if (instances.get(key) == null) {
			// Lazily create instance and try to add it to the map
			Multiton instance = new Multiton();
			instances.putIfAbsent(key, instance);
		}
		
		return instances.get(key);
	}
}

The Java 5 ConcurrentMap.putIfAbsent(), being an atomic operation, returns the previous value associated with the key instead of the new suggested value. This ensures the uniqueness of the Multiton instance inside the ConcurrentMap.

In this solution, before a key object has been associated with a Multiton object, if two or more threads are trying to retrieve the instance with the same key object, it's possible that multiple Multiton instance will be created inside the if() block. However, the ConcurrentMap ensures that a same Multiton instance is  to be returned to the caller. Extra instances are eligible for Garbage Collection as soon as the method returns. You may not want to use this solution if the creation of the Multiton instance is an expensive operation, as in certain situation.
 
 

 

转载于:https://www.cnblogs.com/kid551/p/4653930.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值