单例模式

确保一个类只有一个实例,并提供全局访问点

 

具体做法:

一,将需要设计为单例模式的类的构造方法私有化;

二,单例类定义一个静态变量记录类的唯一实例;

三,单例类定义静态方法getInstance()(这意味着它是类方法,可能在代码的任何地方以类名.getInstance()访问);

四,getInstance()方法首先检查用来保存类例的静态变量是否为空,为空调用构造方法创建实例并返回;不为空直接返回当前实例。

 

例如:

public class Singleton
{
    private static Singleton uniqueInstance;//保存类的唯一实例的静态变量
 
    // other useful instance variables here
    private Singleton()
    {
    }
 
    public static Singleton getInstance()
    {//静态类方法,用于提供访问该类实例的全局点
        if (uniqueInstance == null)
        {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
    // other useful methods here
}


多线程的处理:

常规的单例模式涉及到多线程时可能产生多个实例,造成不可预料的后果,所以在必要时需要针对多线程进行处理:

三种方式:

一,同步getInstance()方法,可能造成效率下降

    public static synchronized Singleton getInstance()
    {//增加synchronized关键字迫使每个线程在进入此方法前,先等候其他线程离开该方法
        if (uniqueInstance == null)
        {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }

 

二,急切实例化,在JVM加载类时马上创建此唯一的单例实例。

public class Singleton
{
    private static Singleton uniqueInstance = new Singleton();//在静态初始化器中创建单例,也就是在任何线程调用该类前完成实例化,保证了线程安全
    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
        return uniqueInstance;
    }
}

 

三,引入双重检查加锁,减少同步使用频率(不适用于JDK1.4及更早版本)

public class Singleton
{
    private volatile static Singleton uniqueInstance;//引入volatile关键字,确保当uniqueInstance被初始化为实例后,多个线程正确处理uniqueInstance变量
    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
        if (uniqueInstance == null)
        {//首先检查是否实例已经创建
            synchronized (Singleton.class)
            {//如未创建,“才”进行同步
                if (uniqueInstance == null)
                {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

 

需要注意的是:

一,单例类并不适合被设计为超类让具体类继承自它;

二,静态初始化的控制权在Java手里,不建议把类的所有方法和变量都定义成静态的(那是“类的单例”),而使用本章单件设计模式实现的是“对象的单件”;

三,不同的类加载器加载同一个单例类,仍然有可能导致单例失效而产生多个实例(同一程序,不同命名空间);

 

要点:

单例模式确保程序中的一个类最多只有一个实例;

单例模式提供访问这个实例的全局点(getInstance());

实现单例模式需要私有的构造方法、一个静态变量和一个静态方法;



补充介绍一下volatile

在Java内存模型中,有main memory,每个线程也有自己的memory(例如寄存器)。为了性能,线程会在自己的memory中保存变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者与main memory中的值不一致的情况。

如果一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中,必须放在main memory里。

即而volatile的作用就是使它修饰的变量的读写操作都必须在内存中进行!