Java单例模式

Java单例模式的几种实现方法:

饿汉模式

线程安全,调用效率高,但是不能延时加载。

1
2
3
4
5
6
7
public class ImageLoader{ 
private static ImageLoader instance = new ImageLoader;
private ImageLoader(){}
public static ImageLoader getInstance(){
return instance;
}
}

特点:
(1)单例模式在类定义中设置为static
(2)类构造函数设置为private
在程序编译的过程中就把单例对象构建出来保存在内存中,是单例模式最简单的实现模式。问题就是在还没有用到单例的时候,初始化就已经加载出来了。如果从头到尾都没有使用这个单例,那么这个单例还是会加载出来占用资源。

懒汉模式

线程安全,调用效率不高,但是能延时加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SingletonDemo2 {

//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)
private static SingletonDemo2 instance;

//构造器私有化
private SingletonDemo2(){}

//方法同步,调用效率低
public static synchronized SingletonDemo2 getInstance(){
if(instance==null){
instance=new SingletonDemo2();
}
return instance;
}
}

使用synchronized保证线程安全。synchronized修饰方法的时候锁定的是调用该方法的对象。它并不能使调用该方法的多个对象在方法执行上进行互斥。
将一个类的构造函数私有化将使这个类不被实例化和不能被继承。要创建这个类的实例,必须创造一个静态的公共方法。这种方式就是懒汉单例模式。

静态内部类实现模式

线程安全,调用效率高,可以延时加载

1
2
3
4
5
6
7
8
9
10
11
12
public class SingletonDemo3 {
//创建静态私有内部类
private static class SingletonClassInstance{
private static final SingletonDemo3 instance=new SingletonDemo3();
}
//同样私有化构造函数
private SingletonDemo3(){}

public static SingletonDemo3 getInstance(){
return SingletonClassInstance.instance;
}
}

参考JVM的类加载原理机制中解析的部分。由于解析的的动态链接属性,将单例存放在内部类中,在加载过程class SingletonDemo3的时候会发现加入了内部类,该内部类不会马上被加载。而是在调用到该类中的成员变量或方法的时候才加载该内部类。即使这个内部类是静态的也不会被当做静态代码块进行加载

枚举类

1
2
3
4
5
6
public enum SingletonDemo4 {
//枚举元素本身就是单例
INSTANCE;
//添加自己需要的操作
public void singletonOperation(){}
}

使用关键字enum定义的枚举类型,在编译期后,也将转换成为一个实实在在的类,而在该类中,会存在每个在枚举类型中定义好变量的对应实例对象。

选用标准

  • 单例对象 占用资源少,不需要延时加载,枚举 好于 饿汉
  • 单例对象 占用资源多,需要延时加载,静态内部类 好于 懒汉式