定义:确保某一个类只有一个实例,而且自行实例化并且向整个系统提供这个实例。
也就是 对象不能通过new 来实例化,而是有类本身来实例化一个自己的对象 ,并且创建一个对于这个对象的get方法。
饿汉单例
将类的对象作为类的成员变量,在类声明的时候就已经实例化。 provate static final objct o = new object(); public object getInstance(){ return o; }
懒汉单例
//在用户第一次调用getInstance的时候进行初始化 public object getInstance(){ if ( o == null ) { o = new object(); } return o; }
Double Check Look (DCL) 单例实现模式
public final class Obj{ private volatile Obj obj ; public Obj getInstance(){ if(obj == null){ synchronized(Obj.class){ if(obj == null){ obj = new Obj(); } } } return obj; } }
.
等
一般 线程安全的解决办法就是 使用volatile关键字来修饰变量,用synchronized来修饰方法体或一个方法块;
例如:
public class SingleObject{ private static volatile SingleObject so = null; public static SingleObject getInstance(){ if(so == null ){ synchronized(SingleObject.class){ if(so == null ){ so = new SingleObject(); } } } } }
可以看到在成员变量是用volatile修饰,可以保证对象每次都是从主内存中读取。
volatile 或多或少的会影响到性能
而get方法中有两层 判断: 第一层是因为 避免直接的不必要的同步, 第二次则是在同步锁内的判断,这一次则是为了创建实例。
这样写的好处就是 在对象实例化过后,调用get方法 将不会再进行同步锁!
解决办法 :
一 、使用枚举单例,没错就是枚举
public enum SingleEnumObject { INSTANCE; public void doSomething(){ System.out.println(" class = " +this); } }
枚举在java中与普通的类是一样的,不仅能够有字段,还能够有自己的方法,最重要的是默认枚举单例的创建时线程安全的,并且任何情况下它都是一个单例。
单例模式一般没有接口,所有扩展起来很难,除非修改代码。