单例设计模式:采取某种方法,对某个类在整个系统中,只有一个对象实例。比如Hibernate 的SessionFactory,一个数据源只需要一个SessionFactory就够了。
适用于频繁创建和销毁的对象,工具类对象,频繁使用数据库或文件的对象(比如数据源,session工厂等)
单例模式 可以细分为以下几种
- 饿汉式(静态常量)
- 饿汉式(静态代码块)
- 懒汉式(线程不安全)
- 懒汉式(同步方法,线程安全)
- 懒汉式(同步代码块,线程不安全)
- 双锁检验
- 静态内部类
- 枚举
饿汉式(静态常量)
public class SingletonTest01 {
public static void main(String[] args) {
//测试
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2); // true
System.out.println("instance.hashCode=" + instance.hashCode());
System.out.println("instance2.hashCode=" + instance2.hashCode());
}
}
//饿汉式(静态变量)
class Singleton {
//1. 构造器私有化, 防止外部new
private Singleton() {}
//2.本类内部创建静态对象实例
private final static Singleton instance = new Singleton();
//3. 提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
分析:
这种写法非常简单,没有线程问题,利用类装载的时候创建对象,但是导致类装载的时机是很多的,因此资源浪费的问题。
资源浪费不是特别严重的问题,因此总体是可以接受的,是可用的。
饿汉式(静态代码块)
class Singleton {
private Singleton() {}//构造方法私有化,防止外部new
//2.本类内部创建对象实例
private static Singleton instance;
static { // 在静态代码块中,创建单例对象
instance = new Singleton();
}
//3. 提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
这种方法和上面的几乎一样,只不过将对象实例化的过程放到了代码块中。优缺点和上面的是一样的。
懒汉式(线程不安全)
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一个静态的公有方法,当使用到该方法时,才去创建 instance
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
起到了懒加载的效果,但是在多线程环境下不安全,可能会创建多个对象实例出来,因此这个方法是不能使用的
懒汉式(同步方法,线程安全)
// 懒汉式(线程安全,同步方法)
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
解决了线程安全的问题,但是效率比较低,如果系统中要频繁的获取对象实例,那么这种方法毫无疑问是不推荐的。
懒汉式(同步代码块,线程不安全)
class Singleton {
private static Singleton instance;
private Singleton() {}
//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
毫无疑问 这是线程不安全的,多线程环境下不能使用这个方法。
双锁检验
class Singleton {
private static volatile Singleton instance;//volatile 抑制指令重排序
private Singleton() {}
//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
//同时保证了效率, 推荐使用
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
线程安全,实现了懒加载,实际中可以使用这种方式。
静态内部类
class Singleton {
private Singleton() {}//构造器私有化
//写一个静态内部类,该类中有一个静态属性 Singleton
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
//提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
public static synchronized Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
在加载外部类Singleton 时候,内部类SingletonInstance 不会被加载,只是在调用外部类的getInstance()方法时,内部类SingletonInstance才会去加载,这种方法线程安全,实现了延迟加载,并且代码简单,推荐使用这种方法
枚举
public class SingletonTest08 {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance == instance2);
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
instance.sayOK();
}
}
//使用枚举,可以实现单例, 推荐
enum Singleton {
INSTANCE; //属性
public void sayOK() {
System.out.println("ok~");
}
}
线程安全,还能防止反序列化重新创建新的对象,这种方法是Effective Java的作者Josh BLoch提倡的方法。 推荐使用这种方法。
JDK中使用的设计模式
JDK中的java.lang.Runtime 类中就用的了饿汉式实现单例模式
网友评论