文章目录
Java设计模式之单例设计模式
一、单例设计模式的介绍
1、介绍
单例设计模式就是采取一定的方法措施保证在整个软件系统中,对该类的实例对象有且仅有一个
。
这里采取的措施是:
- 为了限制该类的对象被随意地创建,需要
保证该类构造方法是私有的
,这样外部类就无法创建该类型的对象。 - 为了方便给客户对象提供对此单例对象的使用,
我们为它提供一个全局访问
。
2、单例模式的两种形式:饿汉式和懒汉式。
饿汉式:在类进行加载的时候就立即实例该实例,这样会造成内存的浪费,这里经常用到的使用static进行修饰,利用的加载机制来实现的,能够避免多线程的问题。
饿汉式有:
- 静态变量
- 静态代码块
枚举类
懒汉式:是只有在需要使用的时候才进行实例化,所以往往需要考虑到多线程的情况,所以使用关键synchronized进行同步等。
懒汉式有:
- 同步同步方法
双检查式
静态内部类
二、单例模式之饿汉式的实现
1、静态常量实现
原理:
- 静态变量在类加载的时候就会进行初始化,所以一旦加载该类,该实例就会立即创建,避免了线程同步的问题
问题:
- 如果没有使用到该单例,就会造成内存的浪费。
步骤:
- 在定义一个实例类,将使用private 将构造方法私有化。
- 对外暴露该实例,供其他类使用,可以是通过静态变量暴露、也可是通过静态方法进行暴露
代码实现:
package design.model.singleton;
public class SingletonStaticField {
/**
* 修饰符说明:
* public static : 向外暴露该实例的获取方式
* final : 防止其他类对改变量的修改
* */
public static final SingletonStaticField singleton = new SingletonStaticField();
// 是私有化构造方法
private SingletonStaticField(){
}
}
2、静态代码块实现
原理:
- Java在加载的时候,会一次执行静态变量以及静态代码块,所以一旦该类被加载的时候,实例就会被初始化。对象实例化过程较为复杂的可以在静态代码块实例化
问题:
- 如果没有使用到该单例,同样会造成内存的浪费。
代码实现:
package design.model.singleton;
public class SingletonStaticBlock {
private static SingletonStaticBlock singleton;
static{
// 再静态代码块中进行实例化,实例化过程较为复杂的可以在静态代码块实例化
singleton = new SingletonStaticBlock();
}
/**
* 私有化
* */
private SingletonStaticBlock(){}
/**
* 对外暴露
* */
public static SingletonStaticBlock getSingleton(){
return singleton;
}
}
3、枚举类实现
原理:
- 借助于JDK1.5以后的枚举类来实现单例模式,能够避免多线程同步问题,而且还能防止反序列化重写创建新的对象,
推荐使用
。
代码实现:
package design.model.singleton;
public enum SingletonEum {
/**
* 实例化该枚举
* */
SINGLE;
}
三、单例模式之懒汉式的实现
1、同步方法实现
原理:
- 每次获取该类的实例时,都会进行同步,保证了线程安全,但是在效率太低,不推荐使用。
代码实现:
package design.model.singleton;
public class SingletonSynMethod {
private static SingletonSynMethod singleton;
/**
* 私有化
* */
private SingletonSynMethod(){}
/**
* 对外暴露
* 提供一个静态的公有方法,加入同步方法的代码,解决线程安全问题
* */
public static synchronized SingletonSynMethod getInstance(){
if(singleton==null){
//为空就进行初始化
singleton = new SingletonSynMethod();
}
return singleton;
}
}
2、同步代码块(双检查法)实现
原理:
- 这里使用
双检查法
,如果只是在进入锁定代码之前检查一次,在多线程中会出现singleton实例化两次的情况,所以需要使用volatile修饰变量
,同时进行两次检查。
代码实现:
package design.model.singleton;
public class SingletonDoubleCheck {
// 修饰符必须使用 volatile
private static volatile SingletonDoubleCheck singleton;
/**
* 私有化
* */
private SingletonDoubleCheck(){}
/**
* 这里使用双检查法
* 在进入代码块前检查一次
* 在进入代码块之后检查一次
* */
public static SingletonDoubleCheck getInstance(){
// 第一次检查
if(singleton==null){
synchronized (SingletonDoubleCheck.class){
// 第二次检查
if (singleton ==null){
singleton = new SingletonDoubleCheck();
}
}
}
return singleton;
}
}
3、静态内部类实现
原理:
- 静态内部类会在需要使用的时候才进行加载,所以只有在我们使用的时候,才会实例化该INSTANCE,达到懒加载的目的。
代码实现:
package design.model.singleton;
public class SingletonStaticInnerClass {
/**
* 私有化构造方法
* */
private SingletonStaticInnerClass(){}
private static class StaticInnerClass{
private static final SingletonStaticInnerClass INSTANCE = new SingletonStaticInnerClass();
}
public SingletonStaticInnerClass getInstance(){
return StaticInnerClass.INSTANCE;
}
}