单件模式:确保一个类只有一个实例,并提供一个全局访问点。
package com.ez.biz;
/**
* 单件模式,
* @author 窗外赏雪(EZ编程网)
*/
public class Singleton {
//利用一个私有静态变量记录类的唯一实例
private static Singleton uniqueInstance;
//私有构造方法,只有类内部才能调用构造方法
private Singleton(){}
//全局访问点
public static Singleton getInstance(){
//延迟实例化
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
单件模式利用Java静态变量也可以做到,但是有以下缺点:
如果将对象赋给一个全局变量,那么你必须在程序一开始就创建好对象。
万一这个对象非常耗费资源,程序在这次的执行中,又没用到它,就会形成浪费了。
单件模式可以延迟实例化。
park停车场,当位置满的时候,就不让车辆进入。
package com.ez.biz;
/**
* 车进入停车场时,判断车位是否有空余。
* @author 窗外赏雪(EZ编程网)
*/
public class Park {
//停车场一共20个车位
private int carports = 20;
//私有静态变量,记录类的唯一实例
private static Park uniquePark;
//全局访问点
public static Park getInstance(){
if(uniquePark==null){
uniquePark=new Park();
}
return uniquePark;
}
//私有构造方法
private Park(){}
//车辆进入
public void enter(){
if(carports>0){
carports--;
}else{
System.out.println("车位已满");
}
}
}
在多线程的情况下,会导致车位已经满了,但是车辆还可以进入。
多线程下,单件模式的处理。
把全局入口getInstance()变成同步,多线程问题就可以解决。
//全局访问点
public static synchronized Park getInstance(){
if(uniquePark==null){
uniquePark=new Park();
}
return uniquePark;
}
一旦设置好uniqueInstance变量,就不再需要同步这个方法了。
很明显,我们需要确保单件模式能在多线程的状况下正常工作,而同步getInstance()的做法将拖垮性能。
第一种做法:
private static Park uniqueInstance = new Park();
在静态初始化器中创建单件。这段代码保证了线程安全。
我们依赖JVM在加载这个类时,马上创建此唯一的单件实例。
JVM保证在任何线程访问uniqueInstance静态变量之前,一定先创建此实例。
第二种做法:
利用“双重检查加锁”,先检查实例是否已经创建,如果还没有创建,才进行同步。这样,只有第一次才会同步。
package com.ez.biz;
/**
* 车进入停车场时,判断车位是否有空余。
* @author 窗外赏雪(EZ编程网)
*/
public class Park {
// 私有静态变量,记录类的唯一实例 vloatile
private volatile static Park uniquePark;
// 全局访问点
public static Park getInstance() {
if (uniquePark == null) {
synchronized (Park.class) {
if (uniquePark == null) { //进入区块后,再检查一次
uniquePark = new Park();
}
}
}
return uniquePark;
}
}