一、单例模式
是java中最简单的设计模式之一。属于创造型模式,提供了一种创建对象的最佳方式。
这种模式是一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
特征:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
使用场景:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
二、简单单列模式的实现
2.1 创建SingleTon类
package com.cf.singleTon;
public class SingleTonDemo {
//创建对象
private static SingleTonDemo instance = new SingleTonDemo();
//构造函数设为private,以防该类被实例化
private SingleTonDemo() {
}
//对外提供方法获取唯一可用的对象
public static SingleTonDemo getInstance() {
return instance;
}
//构造方法
public void hello() {
System.out.println("Hello, this is a singleTon");
}
}
2.2 测试类
package com.cf.singleTon;
public class SingleTonDemoTest {
public static void main(String[] args) {
//编译时即发生错误--The constructor SingleTonDemo() is not visible
//SingleTonDemo singleTon = new SingleTonDemo();
//获取唯一的对象
SingleTonDemo singleTon = SingleTonDemo.getInstance();
singleTon.hello();
}
}
2.3 输出结果
三、单例模式的几种实现方式
以上介绍了最简单的单列,下面介绍多种实现方式,在线程安全以及是否懒加载方式各不相同。
3.1 懒汉式
懒汉式,顾名思义,是lazy初始化。多线程不安全。
因此多线程时不能使用此种方式。
package com.cf.singleTon;
public class LazySingleTonUnsafe {
private static LazySingleTonUnsafe instance;
//构造函数设为private,以防该类被实例化
private LazySingleTonUnsafe() {
}
private static LazySingleTonUnsafe getInstance() {
if(instance == null) {
return new LazySingleTonUnsafe();
}
return instance;
}
}
3.2 懒汉式-线程安全
package com.cf.singleTon;
public class LazySingleTonSafe {
private static LazySingleTonSafe instance;
private LazySingleTonSafe() {
}
private static synchronized LazySingleTonSafe getInstance() {
if(instance == null) {
instance = new LazySingleTonSafe();
}
return instance;
}
}
懒加载,第一次调用时才进行初始化,避免浪费内存。多线程安全,加了synchronized保证单列。但是效率会降低。
3.3 饿汉式
饿汉式即类加载时就初始化,会造成一定程度的内存浪费。
package com.cf.singleTon;
public class HungrySingleTon {
//类装载时实例化
private static HungrySingleTon instance = new HungrySingleTon();
private HungrySingleTon() {
}
public static HungrySingleTon getInstance() {
return instance;
}
}
不需要加锁,执行效率较高,容易产生垃圾。因为没有懒加载的效果。
3.4 双重校验锁
双重检验锁:DCL,double-check locking
可以在线程安全的情况下实现高性能。
package com.cf.singleTon;
public class DCLSingleTon {
private volatile static DCLSingleTon instance;
private DCLSingleTon() {
}
private static DCLSingleTon getInstance() {
if(instance == null) {
synchronized (DCLSingleTon.class) {
if(instance == null) {
instance = new DCLSingleTon();
}
}
}
return instance;
}
}
其中,第一次检查instance是否为null。如果已经instance已经被实例化则直接返回instance,提高效率。
第二次取得类锁后再次检查instance是否被实例化,如果没有则实例化对象。
instance被声明为volatile,是无序写入内容,与java平台的内存模型相关。虽然使用volatile设置顺序一致。但此种方法还有些争议,因为很多JVM没有实现顺序一致性功能。
因此建议使用第三种饿汉方式。