单例singleton:保证一个类只有一个实例。
实现单例模式的基本思想是:1将构造器私有化(private);2、在类的内部创建对象;3、向外暴露一个静态的公共方法。除了使用enum,其余的方法均是以上的三个环节。

饿汉式

public class Singleton {
	// 私有化构造器
	private Singleton() {
		
	}
	
	//	在类中声明并且实例化对象。
	private  static final Singleton  SINGLETON_INSTANCE= new Singleton();
	
	// 方法需要时静态的,因为该类不可被别人实例化,
	// 想要获取该类的对象时,需要Singleton.getSingleton()来获取。
	public static Singleton getSingleton() {
		return SINGLETON_INSTANCE;
	}
}

可以看到这种方式,保证了单例,并且在类加载初始化的时候就完成了实例化,避免了线程同步安全问题。但是存在着内存浪费的问题。

懒汉式

可以发现,该方法实现了让真正需要该对象时才实例化(起到了lazy loading 的效果)。但是可能存在多个线程同时调用getSington()方法,并且同时执行singleton = new Singleton()语句,从而破坏单例原则。所以该方法只适合单线程。
可以对上述代码改进,将方法设置成synchronized

public class Singleton {
	// 私有化构造器
	private Singleton() {
		
	}
	
	//	在类中声明并且实例化对象。
	private  static  Singleton  singleton;
	
	// 方法需要时静态的,因为该类不可被别人实例化,
	// 想要获取该类的对象时,需要Singleton.getSingleton()来获取。
	//用synchronized来保证方法的同步安全,即同时只能一个线程里的方法能执行该方法。
	public static synchronized Singleton getSingleton() {
//		当发现singleton还没有实例化的时候,进行实例化。
		if(singleton == null) {
			singleton = new Singleton();
		}
		return singleton;
	}
}

由于同时只能有一个线程执行该方法,会导致程序的执行效率变低。

双重检查 Double—Check

public class Singleton {
	// 私有化构造器
	private Singleton() {
		
	}
	
	//	在类中声明并且实例化对象。并设置成volatile;
	private  static  volatile Singleton  singleton;
	
	// 方法需要时静态的,因为该类不可被别人实例化,
	// 想要获取该类的对象时,需要Singleton.getSingleton()来获取。
	public static Singleton getSingleton() {
//		当发现singleton还没有实例化的时候,进行实例化。
//		第一次判断;
		if(singleton == null) {
			synchronized (Singleton.class) {
				if(singleton ==null) {  // 第二次判断,保证只有一个对象会被创建。
					singleton = new Singleton();
				}
			}
		}
		return singleton;
	}
}

双重检查可以看做是对懒汉式的一种改进,将同步内容从方法层面改到方法里面的执行语句,从而提高了程序的执行效率。

将对象放入静态内部类

public class Singleton {
	// 私有化构造器
	private Singleton() {
		
	}
//	将对象放入到静态内部类中,
	private static class SingletonInstance{
		private static final Singleton SINGLETON = new Singleton();
	}
//	当第一次使用getSingleton方法时才会去实例化静态内部类,从而实例化对象。
	public static Singleton getSingleton() {
		return SingletonInstance.SINGLETON;
	}
	
}

该方法利用了java的类加载机制,不仅保证了单例原则,还实现了延迟加载。

枚举类型

enum Singleton{
	INSTANCE; 		//属性
	 void method() {
		 System.out.println("枚举里面的方法可以通过变量来调用");
	 }
`

```java
public class Test {

	public static void main(String[] args) {
		Singleton.INSTANCE.method();
	}

}

使用枚举类型来实现的单例,不仅能避免多线程同步问题,而且能防止反序列化重新创建出一个新的对象。