单例模式:深潜水
单例设计模式基本上是用来控制创建许多对象,因此属于家庭创建模式。
早期的趋势是创建一个马克斯的对象,但在某些情况下,我们需要一个固定数量的对象; 这种模式是正确的,来帮助我们。 通常,我们构造函数标记为私有,以确保外部世界不能创建对象,提供了一个静态方法,简单地返回对象。 它创建一个物体只有在没有事先创建。
随着时间的推移,人们意识到这种香草的实现单例,几个问题,这是改善来解决这些问题。 注意,单件不对错; 只要适合你的问题域。
在这次演讲中,我们将看看不同实现的单例。
让我们看看类图:
Paste_Image.png单使用
有几个地方是明智的使用单例模式。 例如:日志记录、缓存、负载平衡、配置、通信(IO避免表现不佳或远程)和数据库连接池。 单例的Java API的一个例子是运行时类。
单例实现
这是香草的方式使用一个立即加载机制,实现一个单例是线程安全的。
public class MySingleton {
private static final MySingleton mySingleton = new MySingleton();
private MySingleton(){}
public static MySingleton getInstance(){
return mySingleton;
}
}
另一方面,这里有一个例子使用延迟加载机制实现单例。 在多线程应用程序中,这将是一个糟糕的方法。
class MySingleton {
private static MySingleton mySingleton;
private MySingleton(){}
public static MySingleton getInstance(){
if(null == mySingleton) {
mySingleton = new MySingleton();
}
return mySingleton;
}
}
一个多线程的方法可以避免竞态条件,以确保它不会违反一个单例的哲学。 但是在下面的例子中,使整个方法“同步”并不是一个好方法,因为我们需要把锁对象创建语句。
class MySingleton {
private static MySingleton mySingleton;
private MySingleton(){}
public synchronized static MySingleton getInstance(){
if(null == mySingleton) {
mySingleton = new MySingleton();
}
return mySingleton;
}
}
下面的多线程的实现方式可以避免竞态条件,以确保它不会违反独立的哲学和双重检查锁定的帮助下使用对象级别的锁会达到相同的。 这个实现保证线程安全; 但一直锁所需的额外的对象是这不是一个很好的实践。 另一个缺点是,有人可以使用类级别锁你的锁的优点是在一个不同的对象
class MySingleton {
private static MySingleton mySingleton;
private static final Object lock = new Object();
private MySingleton(){}
public static MySingleton getInstance(){
if(null == mySingleton) {
synchronized(lock) {
if(null == mySingleton) {
mySingleton = new MySingleton();
}
}
}
return mySingleton;
}
}
另一个multi-threaded-based实现(避免竞态条件)的帮助下可以实现双重检查锁定使用类级别锁。 在这里,将MySingleton对象标记为不稳定将确保变化由一个线程应该在另一个是可见的。 这个实现保证线程安全。
class MySingleton {
private volatile static MySingleton mySingleton;
private MySingleton() {}
public static MySingleton getInstance() {
if (null == mySingleton) {
synchronized(MySingleton.class) {
if (null == mySingleton) {
mySingleton = new MySingleton();
}
}
}
return mySingleton;
}
}
这意味着实现提供了一个聪明的构造函数,将停止单合同违反使用反射。
class MySingleton {
private volatile static MySingleton mySingleton;
//Reflection can't hack to create more than one object.
private MySingleton() throws Exception {
if (null == mySingleton) {
mySingleton = new MySingleton();
} else {
throw new Exception("It's a singleton class; don't expect more object to get produced");
}
}
public static MySingleton getInstance() throws Exception {
if (null == mySingleton) {
synchronized(MySingleton.class) {
if (null == mySingleton) {
mySingleton = new MySingleton();
}
}
}
return mySingleton;
}
}
这是一个非常受欢迎的实现使用一个静态类,这带来了延迟加载和线程安全的权力。
public class MySingleton {
private MySingleton() {}
private static class SingletonUisngInner {
private static MySingleton mySingleton = new MySingleton();
}
public static MySingleton getInstance() {
return SingletonUisngInner.mySingleton;
}
}
在某些情况下,如果你的单例类继承接口可克隆属性,那么你的单例类需要格外小心,防止单例设计合同。 你的单例类应该覆盖的克隆方法和显式地抛出CloneNotSupportedException。
class ClonedClass implements Cloneable {
//Some logic
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class MySingleton extends ClonedClass {
private MySingleton() {}
private static class SingletonUisngInner {
private static MySingleton mySingleton = new MySingleton();
}
public static OneMore getInstance() {
return singletonUisngInner.mySingleton;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
另一个,我们的决赛,非常受欢迎的和智能的方法实现单例使用枚举,而照顾我们到目前为止的所有问题。
public enum EnumSingleton{
INSTANCE;
}
有时,人们谈论单件跨多个jvm,让我们触摸。 单身意味着只有一个对象,我们非常清楚,JVM对象生命周期管理,所以一个共享对象跨多个JVM是不可能的。
但是如果你需要,你可以在一个JVM中创建对象并分发它作为一个序列化的对象,可以使用其他JVM(但是记住,你反序列化,那么请记住,任何静态或标记为瞬态将无法实现,某个地方,打破了单合同)。 你也可以尝试使用RMI服务器对象作为单件来适应您的需要。
学习快乐!