概述:单例模式即采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实力的方法(静态方法)。
单例模式实现步骤:
- 构造器私有化(防止外部new对象)
- 在类的内部创建对象
- 向外暴露一个静态的方法供获取该对象
JDK中Runtime类在创建时使用的是饿汉式
单例模式的八种编码方式:
饿汉式(2种实现方式)
1 饿汉式(静态常量)
class SingletonType1{
//2. 在类的内部创建对象
private final static SingletonType1 singleton = new SingletonType1();
//1. 构造器私有化
private SingletonType1(){}
//3. 向外暴露一个静态的方法供获取该对象
public static SingletonType1 getSingleton(){
return singleton;
}
}
优点:写法简单,在类装载时完成实例化,避免了线程同步问题;
缺点:因为是在类装载时完成实例化,未达到懒加载的效果,若从始至终均未使用到该实例会造成内存浪费
2 饿汉式(静态代码块)
class SingletonType2{
//2. 在类的内部创建对象
private static SingletonType2 singleton;
//1. 构造器私有化
private SingletonType2(){}
static {
singleton = new SingletonType2();
}
//3. 向外暴露一个静态的方法供获取该对象
public static SingletonType2 getSingleton(){
return singleton;
}
}
优缺点同1)
懒汉式(3种实现方式)
1 懒汉式(线程不安全)
class SingletonType3{
//2. 在类的内部创建对象
private static SingletonType3 singleton;
//1. 构造器私有化
private SingletonType3(){}
//3. 向外暴露一个静态的方法供获取该对象,使用到时在创建
public static SingletonType3 getSingleton(){
if(singleton == null){
singleton = new SingletonType3();
}
return singleton;
}
}
优点:达到了懒加载的效果
缺点:只能在单线程的情况下使用,若在多线程下,一个线程进入了if(singleton == null)判断语句,还未来得及往下执行,另一个线程也通过了该判断语句,这时便会产生多个实例,所以不建议使用;
2 懒汉式(线程安全,同步方法)
class SingletonType3 {
//2. 在类的内部创建对象
private static SingletonType3 singleton;
//1. 构造器私有化
private SingletonType3() {
}
//3. 向外暴露一个静态的方法供获取该对象,使用到时在创建,加入同步处理的代码解决线程不安全问题
public static synchronized SingletonType3 getSingleton() {
if (singleton == null) {
singleton = new SingletonType3();
}
return singleton;
}
}
虽然解决了线程安全问题但是效率低下
3 懒汉式(线程不安全,同步代码块)
class SingletonType3 {
//2. 在类的内部创建对象
private static SingletonType3 singleton;
//1. 构造器私有化
private SingletonType3() {
}
//3. 向外暴露一个静态的方法供获取该对象,使用到时在创建,使用不同方法解决线程不安全问题
public static SingletonType3 getSingleton() {
if (singleton == null) {
synchronized (SingletonType3.class) {
singleton = new SingletonType3();
}
}
return singleton;
}
}
不建议使用
双重检查(推荐使用)
class SingletonType3 {
//2. 在类的内部创建对象,volatile保证可见性,当改变时立即更新到内存
private static volatile SingletonType3 singleton;
//1. 构造器私有化
private SingletonType3() {
}
//3. 向外暴露一个静态的方法供获取该对象,使用到时使用同步代码块方式创建
public static SingletonType3 getSingleton() {
if (singleton == null) {
synchronized (SingletonType3.class) {
if (singleton == null){
singleton = new SingletonType3();
}
}
}
return singleton;
}
}
既解决了懒加载的问题也解决了线程安全的问题,同时保证了效率
静态内部类(推荐使用)
class SingletonType3 {
private SingletonType3() {
}
private static class SingletonType3Instance{
private static final SingletonType3 singleton = new SingletonType3();
}
//向外暴露一个静态的方法供获取该对象
public static SingletonType3 getSingleton() {
return SingletonType3Instance.singleton;
}
}
- 当外部的类被装载时静态内部类不会被装载;
- 当调用外部类获取对象的方法静态内部类才会被装载且只装载一次,同时也保证了线程安全;
枚举(推荐使用)
enum SingletonEnum{
INSTANCE;
}
不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象