单例模式
确保一个类只有一个实例,并提供全局访问点
具体做法:
一,将需要设计为单例模式的类的构造方法私有化;
二,单例类定义一个静态变量记录类的唯一实例;
三,单例类定义静态方法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的作用就是使它修饰的变量的读写操作都必须在内存中进行!