单例模式它确保了某个类只有一个实例对象。对于单例模式,一般来说由一个私有的属性(对自己的引用),一个私有的构造,加上一个提供给外部使用的静态方法构成。下面介绍一下单例的几种写法:
一:懒汉式
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton INSTANCE(){
if (singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
为什么叫懒汉式,我们可以看到私有属性并没有在声明的时候实例化,而是在被调用的时候才,故称作为懒汉式。
二:饿汉式
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton INSTANCE(){
return singleton;
}
}
饿汉式跟懒汉式的区别就在于,饿汉式在类初始化时直接创建实例。
三:懒汉式线程安全
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton INSTANCE(){
if (singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
在方法上加上synchronized 关键字可以时我们的单例模式线程安全,但是这是如果有三个用户abc同时访问,如果a先访问了该资源,那么bc只能等待,只有当a释放资源后才能供b,c访问。这样就降低了效率。所以下面我们引入双重校验锁来提升效率。
四:双重校验锁(提升效率)
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton INSTANCE(){
if (singleton == null ) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
我们进入方法后,并没有直接的加上synchronized,而是先判断singleton是否为空,只有为空的时候,接着我们才锁定资源,当用户调用完之后才释放资源。那么我们比较一下上面的写法,同样用户a,b,c进来,比如同时访问,首先判断singleton是否为空,第一次自然都为空,a,b,c都去执行下面的代码,这是a的网速比b,c快,a先获得这么资源,b,c只能等。当a访问完之后,释放资源,b,c进来,再一次判断singleton是否为空,这时singleton已经被a实例化,b,c直接返回实例化的对象,不需要在去作实例化的操作。效率明显提升了。
总结
单例模式为我们提供了一个类的单例,饿汉式本身就是线程安全的,因为我们的方法中直接提供了实例化好后的对象。对于懒汉式而言,线程则是不安全的,因为在判空的时候,有可能多个用户同时进来,会造成实例化多次的情况,所有也提供了线程安全的单例模式。