单例模式
单例模式(SingletonPattern)是 Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式解决的问题
保证一个类仅有一个实例,并提供一个访问它的全局访问点。防止一个全局使用的类频繁地创建与销毁,节省资源,方便管理。
单例模式注意事项
单例类只能有一个实例。单例类必须自己创建自己的唯一实例,其他任何地方无法通过构造方法创建对象,也意味着需要构造方法私有化。单例类必须给所有其他对象提供这一实例。
使用场景
网站的计数器,一般也是采用单例模式实现,否则难以同步。
数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
代码实现
单例模式又分为懒汉模式和饿汉模式,两种的区别在于是不是启动的时候创建对象,饿汉模式不管是否需要对象,都先创建好。懒汉模式是在需要对象的时候,进行对象的创建。本质区别是时间和空间的取舍,懒汉模式是用时间换空间,启动时候不需要创建对象,节省了空间,但是访问对象的时候要判断是否已经创建对象,会浪费一些时间。饿汉模式是用空间换时间,启动的时候创建对象,浪费了一些空间,但是访问的时候,不需要创建对象和判断对象是否存在,节省了时间,提高了效率。
//懒汉模式
public class Singleton {
private Singleton() {
}
private static Singleton instance = null;
/* 静态工程方法,创建实例 缺点非线程安全*/
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class SingletonHungry {
//构造器私有化
private SingletonHungry(){}
private static SingletonHungry instance = new SingletonHungry();
/* 静态工程方法,创建实例*/
public static SingletonHungry getInstance() {
return instance;
}
}
上面的懒汉模式存在一些问题,在多线程的情况下,多个线程同时调用getInstance方法,可能会创建多个对象,违背了单例模式只有一个实例的原则,需要对getInstance进行同步处理。
public class Singleton {
private Singleton() {
}
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
虽然上面的代码可以保证只会创建一个单例,但是效率很低,是对整个getInstance方法加锁,一旦对象已经创建,每次只能有一个线程访问对象,可以通过双检锁的方式进行优化,既可以保证只会创建一个对象,同时又允许多个线程访问实例。
public class Singleton {
private Singleton() {
}
private volatile static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
使用volatile修饰instance属性,保证属性的可见性,只要发生变化对所有线程可见,因为同步代码范围变小,可以提高效率。双检锁可以保证只会创建一个对象实例。
保证单例,还有很多方式,枚举自身是线程安全的,也是一种不错的选择。
public enum Signleton {
INSTANCE;
private Something something;
Signleton() {
something = new Something();
}
public Something getSomething() {
return something;
}
}
优缺点
优点:在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。由于在系统内存中只存在一个对象,因此可以 节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
缺点:不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。 单例类的职责过重,在一定程度上违背了“单一职责原则”。
我的启发
世界上没有两片完全相同的树叶,人何尝不是如此,每个人都是唯一,做最真实的自我。我是幸运的,因为我还活着,珍爱生命,过好每一天。
网友评论