1. 懒汉式
静态变量
public class StaticVariable {
/**
* 1.构造器私有化 外部不能new
*/
private StaticVariable(){}
/**
* 2.本类内部创建对象实例 StaticVariable
*/
private final static StaticVariable singleton = new StaticVariable();
/**
* 提供一个公有的静态方法 返回对象实例
* @return
*/
public static StaticVariable getInstance(){
return singleton;
}
}
静态代码块
public class StaticCodeBlock {
/**
* 1.构造器私有化 外部不能new
*/
private StaticCodeBlock(){}
private static StaticCodeBlock singleton;
/**
* 2.在静态代码块中创建单例对象 从这里可以看出静态变量的执行顺序比静态代码块先执行
*/
static {
singleton = new StaticCodeBlock();
}
/**
* 3.提供一个公有的静态方法 返回对象实例
* @return
*/
public static StaticCodeBlock getInstance(){
return singleton;
}
}
2. 饿汉式
静态方法
//线程不安全 开发不能使用 会违反单例模式的初衷
public class StaticMethod {
private StaticMethod(){}
private static StaticMethod singletonThree;
public static StaticMethod getInstance(){
if (singletonThree == null){
singletonThree = new StaticMethod();
}
return singletonThree;
}
}
同步方法
//(线程安全 同步方法 效率太低 不建议使用) 但是JDK1.8 synchronized锁升级 性能并不差
public class SynchronizationMethod {
private SynchronizationMethod(){}
private static SynchronizationMethod instance;
public static synchronized SynchronizationMethod getInstance(){
if (instance == null){
instance = new SynchronizationMethod();
}
return instance;
}
}
静态内部类加载
//SingletonSeven加载时 SingletonInstance不会加载 加载的时候只会加载一次 能确保懒加载 又能实现单例模式
public class StaticInnerClass {
private StaticInnerClass(){}
private static class SingletonInstance{
private static final StaticInnerClass instance = new StaticInnerClass();
}
public static StaticInnerClass getInstance(){
return SingletonInstance.instance;
}
}
同步代码快
//线程安全 同步代码快 不能起到线程同步的作用 会违反单例模式的初衷 实际开发中不能使用这种写法)原因是Jvm会指令重排 对象的初始化过程中 初始化顺序错乱
public class FastSynchronizationCode {
private FastSynchronizationCode(){}
private static FastSynchronizationCode instance;
private static FastSynchronizationCode getInstance(){
if (instance == null){
synchronized (FastSynchronizationCode.class){
instance = new FastSynchronizationCode();
}
}
return instance;
}
}
双重检查
public class DCL {
private DCL(){}
/**
* volatile 可以让修改的内容立即更新到内存(可见性 有序性---防止指令重排) 可以理解为轻量级的 synchronized
*/
private static volatile DCL instance;
private static DCL getInstance(){
if (instance == null){
synchronized (DCL.class){
if (instance == null){
instance = new DCL();
}
}
}
return instance;
}
}
3. 枚举
//推荐使用 不仅能避免多线程同步问题 还能防止反序列化重新创建新的对象
public enum Enumerate {
INSTANCE;
}
class Test {
public static void main(String[] args) {
System.out.println(Enumerate.INSTANCE == Enumerate.INSTANCE);
}
}
4.应用
我们JDK中,java.lang.Runtime就是经典的单例模式(饿汉式) 源码简单自行查看
单例模式注意事项和细节说明:
- 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
- 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
- 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)