单例模式
使用率最高的设计模式,使用单例模式的类必须保证在整个进程中只会创建该类的1个对象,它属于创造性模式!
优点
1、节省内存空间
2、减少性能开销
缺点
1、可能引起内存泄漏
2、扩展性差
代码关键点
1、private修饰构造方法,表示不允许其他人通过构造方法创建对象
2、private修饰一个static变量,static变量负责持有创建的唯一的单例对象(单例类持有单例对象)
3、public修饰的static方法返回唯一创建的单例对象
4、确保多线程下可使用单例对象
5、确保反序列化时不会创建新的对象
第一种方式(饿汉模式):定义static变量时,同时立即创建单例对象
缺点:类加载到JVM内存中时,立刻创建了单例对象,影响类加载到JVM内存时的性能
优点:线程安全(依赖类加载机制)
说明:这种写法常被称为饿汉模式,the singleton instance is early created at complie time中的early直接音译过来的,因为对象创建的时机非常的早……不知道是谁这么翻译的……音译……还是表示特别的饿……
public class SingleTest {
private SingleTest() {
super();
System.out.println("SingleTest()");
}
private static SingleTest Instance = new SingleTest();
public static SingleTest getInstance() {
System.out.println("getInstance()");
return Instance;
}
public static void main(String args[]) {
SingleTest sTest = getInstance();
}
}
第二种方式(懒汉模式)
定义static变量负责持有单例对象(类负责持有单例对象),单例对象则延迟在静态方法被调用时创建
缺点:不支持多个线程同时调用创建对象的静态方法getInstance(),非线程安全
优点:调用静态方法时才会创建单例对象,实现了懒加载,保证了类加载JVM时的加载效率
说明:这种方式常被称为懒汉模式,the singleton instance is lazily created at runtime中的lazily的音译,因为对象创建的比较晚!这翻译太糟糕……而且还传开了……
public class SecSingle {
private static SecSingle instance;
private SecSingle(){
super();
}
public static SecSingle getInstance() {
if (instance == null) {
instance = new SecSingle();
}
return instance;
}
}
第三种方式(同饿汉模式)
类加载到JVM时,在静态代码块中创建单例对象
缺点:类加载到JVM内存时创建了对象,影响类加载到JVM内存中的性能
优点:线程安全
说明:同本文第一种方式完全一样,只是写法不同而已……,staitc语句最终都会在JVM生成的一个类构造器方法<clinit>中执行的
class ThirdSingleton {
private static ThirdSingleton instance;
private ThirdSingleton(){
}
static {
instance = new ThirdSingleton();
}
public static ThirdSingleton getInstance(){
return instance;
}
}
第四种方式(同饿汉模式)
缺点:类加载时即创建对象,影响类加载到JVM内存中的性能
优点:线程安全
说明:同本文第一种方式,只不过static变量由final修饰……
class FourthSingleton {
private final static FourthSingleton mInstance = new FourthSingleton();
private FourthSingleton(){
}
public static FourthSingleton getInstance() {
return mInstance;
}
}
第五种方式
同步静态方法调用时创建单例对象
缺点:静态方法使用synchronized修饰,当单例对象已经创建,其它的线程仍然需要再次持有对象锁(Class对象的锁)后才能访问该静态方法,线程获取锁与释放锁会影响运行效率
优点:线程安全
说明:不推荐使用该方式,静态方法被调用时,需要获取与释放对象锁,影响性能
class FifthSingleton {
private static FifthSingleton mInstance;
private FifthSingleton(){
super();
}
public static synchronized FifthSingleton getInstance(){
if(mInstance == null){
mInstance = new FifthSingleton();
}
return mInstance;
}
}
第六种方式
静态方法调用时创建单例对象
缺点:线程不安全,因同步代码块的范围加的不正确,2个线程有可能已经同时进入if(mInstance == null)的代码块,此时会造成每个线程都去创建一个对象
优点:懒加载,对象创建时机晚,使用时创建的对象
class SixthSingleton {
private static SixthSingleton mInstance;
private SixthSingleton(){
super();
}
public static SixthSingleton getInstance(){
if(mInstance == null) {
synchronized (SixthSingleton.class) {
mInstance = new SixthSingleton();
}
}
return mInstance;
}
}
第七种方式
采用双重校验锁的静态方法创建单例对象(Double Check Lock,DCL)
缺点:相对来说已经无缺点(推荐使用)
优点:线程安全(推荐使用),传说中的双重校验锁方式,弥补了第六种方式的bug,只有对象未创建时线程才会持有对象锁,当线程持有对象锁后,会在同步代码块中继续判断对象是否已经创建?未创建的情况才会创建对象,这样即确保线程安全,又确保效率第一(线程不必每次访问该静态方法都持有对象锁)
class SeventhSingleton {
private static SeventhSingleton mInstance;
private SeventhSingleton(){
}
public static SeventhSingleton getInstance(){
if(mInstance == null) {
synchronized (SeventhSingleton.class) {
if(mInstance == null) {
mInstance = new SeventhSingleton();
}
}
}
return mInstance;
}
}
第八种方式
静态内部类加载到JVM时创建单例对象
缺点:无明显的缺点(推荐使用)
优点:线程安全,利用类加载机制确保线程安全,又利用使用单例对象时才加载到JVM内存中,即保证线程安全,又保证类加载到JVM内存中的效率,牛逼!
class EighthSingleton {
private EighthSingleton(){
super();
}
private static class Single {
private static final EighthSingleton INSTACE = new EighthSingleton();
}
public static EighthSingleton getInstance(){
return Single.INSTACE;
}
}
第九种方式
利用HashMap对象持有多个单例对象!等待…………
…………