单例模式指的是在一个系统中,一个类有且仅有一个对象
- 单例模式只能有一个实例
- 单例类必须自己创建自己的唯一实例
- 单例类必须给所有其他对象提供这一实例
1、懒汉式单例,线程不安全
public class LazySingleton {
private static LazySingleton instance;
// 构造器私有避免在外部被实例化
private LazySingleton(){
}
public static LazySingleton getInstance(){
if (instance == null) {
System.out.println(LazySingleton.class);
instance = new LazySingleton();
}
return instance;
}
}
但是使用多线程的方式创建该实例发现实例不是唯一的
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton(){
}
public static LazySingleton getInstance(){
if (instance == null) {
System.out.println(LazySingleton.class);
instance = new LazySingleton();
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazySingleton.getInstance();
}).start();
}
}
}
2、懒汉式单例,线程安全,可以在创建实例的方法中加同步方法(Synchronized)
public static synchronized LazySingleton getInstance(){
if (instance == null) {
System.out.println(LazySingleton.class);
instance = new LazySingleton();
}
return instance;
}
3、懒汉式,双重检验锁,这里两次检查instance == null,是因为,如果在获取锁之前,两个线程都进入第一个判断之后,其中一个获取锁失败,进入阻塞状态等待,等前面的线程释放锁之后,就拿到锁,创建对象,所以不进行两次判断将可能new除一个新的对象。
public static LazySingleton getInstance(){
if (instance == null) {
synchronized (LazySingleton.class){
if (instance == null){
System.out.println(LazySingleton.class);
instance = new LazySingleton();
}
}
}
return instance;
}
4、懒汉式,volatile 修饰instance,保证其指令不可重排。
public class LazySingleton {
private static volatile LazySingleton instance;
private LazySingleton(){
}
public static LazySingleton getInstance(){
if (instance == null) {
synchronized (LazySingleton.class){
if (instance == null){
System.out.println(LazySingleton.class);
instance = new LazySingleton();
}
}
}
return instance;
}
5、饿汉式单例
- 饿汉式单例,在类初始化时就已经自行实例化
- 饿汉式在类创建得同时就已经创建好静态对象供系统使用,以后不再改变,天生线程安全
public class HungryMan {
private static HungryMan HUNGRYMAN = new HungryMan();
private HungryMan(){
}
public static HungryMan getInstance(){
return HUNGRYMAN;
}
}
6、静态内部类
public class Singleton {
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
7、枚举的方式
public enum SingletonEnum {
INSTANCE;
}
除了开头第一个懒汉式单例,其余的都是线程安全的单例模式。