单例模式:确保一个类只有一个实例并提供一个全局访问点
技术应用:线程池,缓存,对话框,日志对象,充当打印机
真实场景应用:某食品有一个工业强度巧克力锅炉控制器,比如锅炉已经满了还继续放入原料,或者锅炉内还没放入原料就开始空烧。这样的话,如果同时存在两个控制器实例的话,那么很可能会发生很糟糕的事情。
于是,我们开始对单例模式的探讨。
单例类特点:
1、对构造方法私有化
2、返回静态内部对象
于是有:
package com.design.singleton;
public class Singleton {
private static Singleton singleton;
private Singleton(){};
public static Singleton getSingleton(){
//延迟加载判断
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
我们在静态对象方法内部加入内延迟加载的效果,如果不需要用到该类,那么都不会去实例化该对象。
但是,这样的设计在多线程中确实会出现问题,我们写个测试方法在多线程下做下测试,
线程类:
package com.design.singleton;
/**
* 单例模式在线程下的测试
* @author Administrator
*
*/
public class SingletonInThread extends Thread{
@Override
public void run() {
super.run();
try {
Thread.sleep(3000);
//打印对象的哈希码
System.out.println(Singleton.getSingleton().hashCode());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
然后测试:
package com.design.singleton;
/**
* 单例模式在线程下的测试
* @author Administrator
*
*/
public class SingletonInThread extends Thread{
@Override
public void run() {
super.run();
try {
Thread.sleep(3000);
//打印对象的哈希码
System.out.println(Singleton.getSingleton().hashCode());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试结果:
发现出现了多例对象。
于是我们这样去改进:
package com.design.singleton;
public class RapidSingleton {
public static RapidSingleton rapidSingleton = new RapidSingleton();
private RapidSingleton(){};
public static RapidSingleton getsRapidSingleton(){
return rapidSingleton;
}
}
测试线程:
package com.design.singleton;
/**
* 单例模式在线程下的测试
* @author Administrator
*
*/
public class SingletonInThread extends Thread{
@Override
public void run() {
super.run();
try {
Thread.sleep(3000);
//打印对象的哈希码
System.out.println(RapidSingleton.getsRapidSingleton().hashCode());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试结果:
这样就确保了一个类只有一个实例,但是却还是有问题,违背了我们想让单例模式延迟加载的初衷,于是我们想到了同步方法(但是我们知道,加入同步关键字,性能会下载一百倍以上),不过,先试试行不行,于是有:
package com.design.singleton;
public class SyncSingleton {
private static SyncSingleton syncSingleton;
private SyncSingleton(){};
//在外层加入同步关键字,性能会降低100倍以上
synchronized public static SyncSingleton getSingleton(){
if(syncSingleton == null){
syncSingleton = new SyncSingleton();
}
return syncSingleton;
}
}
同理去测试,得到测试结果:
package com.design.singleton;
public class VolatileSingelton {
private volatile static VolatileSingelton singleton = null;
//使用DCL双检测机制来解决问题,既保证了不需要同步代码的一异步执行性
//又保证的单例的效果
private VolatileSingelton(){};
public static VolatileSingelton getSingleton(){
synchronized(VolatileSingelton.class){
if(singleton == null){
singleton = new VolatileSingelton();
}
}
return singleton;
}
}
得到测试结果:
我们发现这个方法是可行的哈。大功告成,Java里面的机制简直太棒了,这样我们就不担心锅炉控制器出现问题咯。