写在最前面
这是第一次写博客,如果有什么建议的话欢迎大佬们评价~
几种简单的单例模式
简单的来说单例模式分为两种:懒汉模式和饿汉模式。所谓的懒汉模式就是在没有使用的时候,你要使用的对象不会被创建,当真正的使用的时候(也就是调用要创建的方法的时候)才会被创建,相对的饿汉模式一开始初始化改类的时候对象的引用就已经创建了。这涉及到类的加载机制,后面的例子会详细的说明。
懒汉模式
- 静态内部类实现单例模式:
// 静态内部类实现单例
class Singletest1{
// 私有构造器
private Singletest1(){
}
// 静态内部类
private static class innerClass{
private static Singletest1 singletest1 = new Singletest1();
}
// 获得实例的公开方法
public static Singletest1 getInstance(){
return innerClass.singletest1;
}
}
解释说明:
类(Singletest1)的加载过程中,静态内部类不会被加载,不同于这个类中的静态变量和静态代码块会在链接的时候就开始初始化执行,当使用了Singletest1的静态方法getInstance()的时候,相当于初始化了静态内部类,这个时候内部类的静态变量才开始初始化生成对Singletest1对象的引用。
- 静态常量实现单例
// 静态常量实现单例
class Singletest2{
// 私有构造器
private Singletest4(){
}
// 私有静态变量Singletest2对象
private static Singletest2 singletest4 = null;
// 公开获得实例方法
public static Singletest2 getInstance(){
if (singletest2 == null){ // 判断是否创建了Singletest2对象
singletest2 = new Singletest2();
}
return singletest2;
}
}
解释说明:
类(Singletest2)在加载链接的时候就会对静态变量singletest2开始初始化(值为null,几乎不占用内存),当调用getInstance()方法的时候才生成Singletest2的实例。
饿汉模式
- 静态常量实现单例
// 静态常量实现单例
class Singletest3{
// 私有构造器
private Singletest3() {
}
// 静态常量
private final static Singletest3 SINGLETEST3= new Singletest4();
// 公开方法
public static Singletest3 getInstance(){
return SINGLETEST3;
}
}
解释说明:
类(Singletest3)在加载的过程中会在链接的准备阶段就会对静态常量Singletest3进行初始化成Singletest3的一个引用且这个值不能在改变。
-
// 静态代码块实现单例
class Singletest4{
private Singletest4(){}
private final static Singletest4 singletest;
static {
singletest4 = new Singletest4();
}
public static Singletest4 getInstance(){
return singletest4;
}
}
解释说明: 和上述的过程一样,不同的是对singletest4初始化放在了静态代码块中。
总结
懒汉模式中第一种内部静态类的实现方式不会涉及到线程安全问题,但是在第二种的实现方式中会涉及到线程的安全问题,需要加锁。读者可以自行创建两个线程实践一下。饿汉模式不会涉及到线程的安全问题,因为一开始要使用的类的对象就创建出来了且不可改变。当要涉及到对一个对象频繁操作的时候,建议使用饿汉模式,否则使用懒汉模式(静态内部类的实现方式最好不用考虑线程安全问题)。饿汉模式如果没有使用对象的时候,因为那个对象一直就存在,所以会浪费内存。