一、饿汉式
在类被加载的时候就完成了创建,以后就使用这个实例。
- 优点:在类加载的时候就完成了初始化,所以避免多线程之类的问题
- 缺点:不管有没有使用这个类,这个类都会实例化出来,会造成内存浪费。
public class SingleTon {
// 将构造方法私有化
private SingleTon(){}
// 创建好一个私有的实例
private static SingleTon instance = new SingleTon();
// 提供一个静态方法用于返回这个单例
public static SingleTon getInstance() {
return instance;
}
}
二、懒汉式
这个类第一次被使用的时候才会去实例化对象,以后都是去使用这个对象
实现方式一
- 优点:起到懒加载的作用
- 缺点:会引发多线程的问题,从而创建出多个实例,即两个线程同时进入getInstance方法,第一个线程判断instance == null后,线程就挂起了。然后第二个判断 instance == null后,执行instance = new SingleTon(),并返回这个实例,然后第一个线程开始执行了,执行instance = new SingleTon(),此时就创建了两个实例了。所以使用的时候不推荐使用这个。
public class SingleTon {
// 将构造方法私有化
private SingleTon(){}
// 创建好一个私有的实例
private static SingleTon instance = null;
// 提供一个静态方法用于返回这个单例
public static SingleTon getInstance() {
if (instance == null) {
instance = new SingleTon();
}
return instance;
}
}
实现方式二
- 优点:起到懒加载的作用。加了锁,不会出现线程问题。
- 缺点:每个线程进来的时候都必须要先获取锁,效率太差
public class SingleTon {
// 将构造方法私有化
private SingleTon(){}
// 创建好一个私有的实例
private static volatile SingleTon instance = null;
// 提供一个静态方法用于返回这个单例
public static synchronized SingleTon getInstance() {
if (instance == null) {
instance = new SingleTon();
}
return instance;
}
}
实现方式三
- 优点:起到懒加载的作用,线程安全,效率较高。
注意点:instance必须使用volatile修饰,作用是防止指令重排,不加这句可能使用的对象还没有初始化完成。
推荐使用
public class SingleTon {
// 将构造方法私有化
private SingleTon(){}
// 创建好一个私有的实例
private static volatile SingleTon instance = null;
// 提供一个静态方法用于返回这个单例
public static SingleTon getInstance() {
if (instance == null) {
synchronized (SingleTon.class) {
if (instance == null) {
instance = new SingleTon();
}
}
}
return instance;
}
}
三、静态内部类
- 静态内部类方式在 SingleTon 类(父类)被装载时,不会导致内部类被装载,也就不会立即实例化,属于懒加载类型。当调用 getInstance() 方法时,才会装载 SingleTonInstance 类,从而完成SingleTon 的实例化。
- 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM 帮我们保证了线程的安全,在类初始化时,别的线程无法进入。
- 避免了线程不安全,利用静态内部类特点实现延迟加载,效率高。
public class SingleTon {
// 将构造方法私有化
private SingleTon(){}
// 在内部类中创建一个对象的实例,当父类SingleTon加载时,内部类无需加载,起到懒加载的作用
private static class SingleTonInstance {
private static SingleTon instance = new SingleTon();
}
// 提供一个静态方法用于返回这个单例
public static SingleTon getInstance() {
return SingleTonInstance.instance;
}
}
四、枚举类
当Java虚拟机第一次加载枚举类时,它会自动创建枚举类的所有实例,所以是线程安全的,可放心使用。
enum SingleTon {
// 当只有一个对象时就是单例
INSTANCE;
}