概念:
单例模式确保该类在系统中只存在一个类的实例,而且自行实例化并向整个系统提供这个实例
特点:
从单例的概念中可以知道
1.单例只能有一个实例
2.单例必须自己创建自己唯一的实例
3.单例需向所有类提供这一实例
使用场景:
在计算机系统中,线程池,日志,缓存,打印机,驱动程序,任务管理器,回收站等通常都设计为单例对象
在日常编程中,如配置文件的读取,数据库连接池,文件操作 等等
编码实例一(经典):
public class Singleton {
private static Singleton uniqueInstance = null;
private Singleton() {
// Exists only to defeat instantiation.
}
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// Other methods...
}
编码实例二(线程中):
public class Singleton {
private static Singleton uniqueInstance = null;
private Singleton() {
// Exists only to defeat instantiation.
}
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// Other methods...
}
编码实例三(饿汉式):
public class Singleton {
private Singleton1() {}
//已经自行实例化
private static final Singleton uniqueInstance = new Singleton();
public static Singleton getInstance() {
return uniqueInstance;
}
}
编码实例四(懒汉式):
public class Singleton {
private Singleton() {}
private static Singleton uniqueInstance = null;
public synchronized static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
编码实例五(登记式):
import java.util.HashMap;
import java.util.Map;
public class Singleton {
private static Map<String,Singleton> map = new HashMap<String,Singleton>();
static{
Singleton uniqueInstance = new Singleton();
map.put(uniqueInstance.getClass().getName(), uniqueInstance);
}
protected Singleton(){}
public static Singleton getInstance(String name) {
if(name == null) {
name = Singleton.class.getName();
System.out.println("name == null"+"--->name="+name);
}
if(map.get(name) == null) {
try {
map.put(name, (Singleton) Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return map.get(name);
}
public String about() {
return "Hello, I am RegSingleton.";
}
public static void main(String[] args) {
Singleton single = Singleton.getInstance(null);
System.out.println(single.about());
}
}
Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)
但是以上实现没有考虑线程安全问题。所谓线程安全是指:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。显然以上实现并不满足线程安全的要求,在并发环境下很可能出现多个Singleton实例。
public class Singleton {
private static Singleton uniqueInstance = null;
private Singleton() {
// Exists only to defeat instantiation.
}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (uniqueInstance) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
// Other methods...
}