回顾概念:
Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,我在这里主要介绍两种:懒汉式单例和饿汉式单例。
单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。
一、懒汉模式
懒汉模式:类加载器在加载类的时候,不会创建实例,只有当需要创建对象的时候,才会去创建类的实例。
1、最简单的,但不是线程安全的懒汉模式。
public class Singleton {
//私有化构造方法,防止外部使用new来创建对象。
private Singleton () {}
private static Singleton single = null;
public static Singleton getInstance () {
if(single == null) {
single = new Singleton();
}
return single;
}
}
2、线程安全的懒汉模式,但是实际运行中效果很差,类似数据库中的表锁。
public class Singleton {
//私有化构造方法,防止外部使用new来创建对象。
private Singleton () {}
private static Singleton single = null;
public static synchronized Singleton getInstance () {
if(single == null) {
single = new Singleton();
}
return single;
}
}
3、双重校验锁,类似数据库中的行锁
public class Singleton {
//私有化构造方法,防止外部使用new来创建对象。
private Singleton () {}
//volatile关键字用于线程可见
private static volatile Singleton single = null;
public static Singleton getInstance () {
if(single == null) {
//锁住类对象
synchronized(Singleton.Class) {
if(single == null) {
single = new Singleton();
}
}
return single;
}
}
}
4、静态内部类方法
public class Singleton {
//私有化构造方法,防止外部使用new来创建对象。
private Singleton () {}
private static class LazyHolder {
//被final修饰的实例变量是无法被修改的,这就保证的对象的唯一性
private static final Singleton single = new Singleton();
}
public static Singleton getInstance() {
return LazyHolder.single;
}
}
二、饿汉模式
饿汉模式:类加载器加载的过程中,就已经创建好实例,因为是在类加载初始阶段就已经加载好了实例,所以饿汉模式总是线程安全的。
5、最简单的,
public class Singleton {
//私有化构造方法,防止外部使用new来创建对象。
private Singleton () {}
//被final修饰的实例变量是无法被修改的,这就保证的对象的唯一性
private static final Singleton single =new Singleton();
public static synchronized Singleton getInstance () {
return single;
}
}
6、与5同理,但是代码实现方式不同
public class Singleton {
//私有化构造方法,防止外部使用new来创建对象。
private Singleton () {}
//被final修饰的实例变量是无法被修改的,这就保证的对象的唯一性
private static final Singleton single = null;
//被static修饰的静态代码块会在类加载期间,类加载器直接运行。
static {
single = new Singleton();
}
public static synchronized Singleton getInstance () {
return single;
}
}
总结:建议在选择单例模式的时候选择用双重校验锁或静态内部类的方式,这两种方式能够实现并发效率最优,但是当你确定某个类一定会被创建实例时,饿汉也是不错的选择。
参考博客:
JAVA设计模式之单例模式