单例模式的实现方式:
静态变量/静态代码块方式
同步方法方式
双重验证方式
静态内部类方式
静态常量/静态代码块方式(不推荐)
优点:写法简单,不需要加锁,使用类加载的时候直接实例化,避免同步分问题
缺点:饿汉式(也就是非懒加载),如果程序运行的时候不需要使用到,那么就会导致内存浪费
public class Singleton{
private static final Singleton INSTANCE = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return INSTANCE;
}
{
INSTANCE = new Singleton();
}
}
同步方法(不推荐)
优点:线程安全,保证了单例,懒加载(需要的时候创建)
缺点:性能太低,创建实例的只需要一次,其他的线程不应该再加锁而是可以直接return得到实例
public class Singleton{
private static Singleton instance;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
双重验证方式(不是很推荐)
优点:懒加载,线程安全确保单例,其他的线程可以直接return获得到单例而不用获得锁——相对同步方法提高了点效率
缺点:同步加锁导致效率仍然不会太高
问题:里面的if(instance == null)有没有必要?
有必要!比如说现在有2个线程,都执行了外面的if(instance == null),然后其中一个线程获取到Singleton.class对象的锁,
然后执行instance = new Singleton()的操作,执行完之后释放锁,另外一个线程2这个时候申请到了锁,然后也执行了这个操作,
new了一个新的对象出来,那么就会导致非单例的出现!
public class Singleton{
private static Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
return instance;
}
}
}
静态内部类方式(推荐!!!)
优点:保证单例,不需要加锁,懒加载(静态内部类并不会像类的静态方法一样,在初始化类的时候就被实例化创建,而是在需要的时候被创建);而且类的静态属性只会在第一次加载类的时候初始化,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的
public class Singleton{
private Singleton(){
}
private static class Inner{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return Inner.INSTANCE;
}
}
下面分析一些不能实现单例模式的例子
错误1:
优点: 懒加载
缺点:线程不安全,多线程下会产生多个实例
public class Singleton{
private static Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
if( instance == null){
instance = new Singleton();
}
return instance;
}
}
错误2:
优点:懒加载
缺点:未能保证单实例,因为如果有2个线程同时通过了if判断,然后就轮流获取Singleton.class锁,创建实例。
改进:改进后的就是双重验证——可以确保单实例
public class Singleton{
private static Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}