定义:一个类有且仅有一个实例,并且自行实例化向整个系统提供。
作用:解决一个全局使用的类频繁地创建与销毁的问题。
优点:减少内存开销,避免对资源的多重占用。
缺点:没有接口,不能继承。
实现方式:饿汉式,懒汉式,双重检查锁,静态私有内部类,枚举
饿汉式
/* 饿汉式单例类*/
public class Singleton {
private Singleton(){
}
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
缺点:不支持并发,只能在单线程中使用,加载时就已经创建好了实例,不管用不用。
懒汉式
懒汉式(不支持并发)
/* 懒汉式-- 不支持并发 */
public class Singleton2 {
private Singleton2(){
}
private static Singleton2 instance = null;
private static Singleton2 getInstance(){
if (instance == null){
instance = new Singleton2();
}
return instance;
}
}
缺点:不支持并发,只能在单线程中使用。
优点:只有在调用获取实例的方法时才创建实例。
懒汉式(支持并发)
/*饿汉式--支持并发*/
public class Singleton3 {
private Singleton3(){
}
private static Singleton3 instance = null;
private synchronized static Singleton3 getInstance(){
if (instance == null){
instance = new Singleton3();
}
return instance;
}
}
缺点:synchronized锁住了整个方法,当有多个线程需要访问方法时,不管实例有没有创建,都需要排队等待才能拿到实例,效率低。
两个懒汉式的区别:加不加 sybchronized。
双重检查锁、volatile(常用)
public class Singleton4 {
private Singleton4(){
}
private volatile static Singleton4 instance = null;
private static Singleton4 getInstance(){
if (instance == null){ //1
synchronized (Singleton4.class){
if (instance == null){ //2
instance = new Singleton4();
}
}
}
return instance;
}
}
volatile 关键字保证了内存可见性,所有线程都会去主存中取数据而不是在线程的缓存中取,保证了数据的更新能实时地对任何线程可见。
假如有两个线程同时到达了1,它们都去创建实例,这时候如果没有第二次判断,就会多次创建实例了。二次判断保证了多线程下只创建一个实例。
静态内部私有类(常用)
public class Singleton5 {
private Singleton5(){
}
private static class Singleton5Holder{
private static Singleton5 instance = new Singleton5();
}
public static Singleton5 getInstance(){
return Singleton5Holder.instance;
}
}
静态内部类不会随着外部类的加载而加载 ,只有静态内部类的静态成员被调用时才会进行加载(实例化)。同时,虚拟机会保证一个类的构造器方法在多线程环境中被正确地加载,同步,如果多个线程同时去初始化一个类,那么只有一个线程去执行这个类的。所以这种方法支持多并发,效率高。
枚举
public enum Singleton6 {
INSTANCE;
}
外部调用由原来的Singleton.getInstance变成了Singleton.INSTANCE了。