- 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
- 在我们的系统中,有些对象其实只需要一个,比如说,线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。
- 这类对象只能有一个对象,制造多个可能会导致一些问题的产生:比如程序的行为异常、资源使用过量、或者不一致性的结果
- 优点:
- 对于频繁使用的对象,可以省略创建对象所花费的时间
- 由于 new 操作的次数减少,对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间
- 饿汉方式:全局的单例实例在类加载时构建
- 懒汉方式:全局的单例模式在第一次被使用时构建
public class Singleton {
//在静态初始化器中创建单例实例,这段代码保证了线程安全
private static Singleton uniqueInstance = new Singleton();
//Singleton类只有一个构造方法并且是被private修饰的,所以用户无法通过new方法创建该对象实例
private Singleton(){}
public static Singleton getInstance(){
return uniqueInstance;
}
}
-
- JVM 在加载这个类时就创建了此唯一的单例实例,不会存在多个线程创建多个实例的情况,所以线程安全
- 缺点:这个单例即便没有被使用也会被创建,在类加载之后就被创建,内存就浪费了
public class Singleton {
private static Singleton uniqueInstance;
private Singleton (){
}
//没有加入synchronized关键字的版本是线程不安全的
public static synchronized Singleton getInstance() {
//判断当前单例是否已经存在,若存在则返回,不存在则再建立单例
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
-
- 在第一次被使用时创建,如果单例已经被创建了,再次调用接口将不会重新创建新的对象,而是直接返回之前创建的对象
- 优点:如果某个单例使用的次数很少,并且创建单例消耗的资源较多,那么就需要实现单例的按需创建,使用懒汉模式是个不错的选择
- 缺点:效率低,第一次加载需要实例化,反应稍慢
public class Singleton {
//volatile保证,当uniqueInstance变量被初始化成Singleton实例时,多个线程可以正确处理uniqueInstance变量
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getInstance() {
//检查实例,如果不存在,就进入同步代码块
if (uniqueInstance == null) {
//只有第一次才彻底执行这里的代码
synchronized(Singleton.class) {
//进入同步代码块后,再检查一次,如果仍是null,才创建实例
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
-
- 利用双重检查加锁,首先检查实例是否已经创建,如果尚未创建,才进行同步。
- 优点:资源利用率高,进行了双重的判断,第一层判断主要避免了不必要的同步
- 缺点:第一次加载时稍慢。
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getUniqueInstance() {
return SingletonHolder.INSTANCE;
}
}
-
- 利用了类加载机制来保证只创建一个实例,与饿汉模式一样,也是利用了类加载机制,因此不存在多线程并发的问题
- 不同的是,是在内部类里面去创建对象实例,这样的话,只要应用中不使用内部类,JVM 就不会去加载这个单例类,从而实现了懒汉方式的延迟加载
public enum Singleton {
INSTANCE;
private String objName;
public void doSomething() {}
}
-
- 相对于其他单例来说,写法最为简单,并且任何情况下都是单例的。jdk 1.5 之后才有的。