巧克力工厂需要将牛奶和巧克力混合,因此需要一个巧克力锅炉,具体代码如下:
public class ChocolateBoiler{
private boolean empty; // 判断是否为空
private boolean boiled; // 判断是否煮沸
public ChocolateBoiler(){ // 刚开始时锅炉是空的
empty = true;
boiled = false;
}
public void fill(){
// 锅炉为空时
if(isEmpty()){
empty = false;
boiled = false;
// 开始填充牛奶和巧克力
}
}
public void drain(){
if(!isEmpty() && isBoiled()){ // 如果锅炉满了而且已煮过
// 排除煮沸的巧克力和牛奶
empty = true; // 锅炉重新变为空
}
}
public void boil(){
if(!isEmpty() && !isBoiled()){ // 如果锅炉满了而且未煮过
// 将混合物煮沸
boiled = true; // 已经煮沸了
}
}
public boolean isEmpty(){
return empty;
}
public boolean isBoiled(){
return boiled;
}
}
确保一个类只有一个实例,并且提供一个全局访问点
因为只允许一个巧克力锅炉存在,所以自然就想到使用单例模式
这种方式十分简单,但是存在线程不安全的问题(图中出现
obj1
和obj2
)
public class ChocolateBoiler{
private boolean empty;
private boolean boiled;
private static ChocolateBoiler uniqueInstance; // ① 静态变量记录ChocolateBoiler类的唯一实例
public static ChocolateBoiler getInstance(){ // ② 提供一个公共方法让外部可以获取到该唯一实例
if(uniqueInstance == null){
uniqueInstance = new ChocolateBoiler();
}
return uniqueInstance;
}
private ChocolateBoiler(){ // ③ 将构造方法改为私有,只有ChocolateBoiler类内部才能调用
empty = true;
boiled = false;
}
// 其他代码一致
}
既然存在多线程问题,不如将
getInstance
方法改为同步方法这样虽然可以解决线程安全问题,但是性能实在过于低下
public class ChocolateBoiler{
// 加上synchronized关键字
public static synchronized ChocolateBoiler getInstance(){
if(uniqueInstance == null){
uniqueInstance = new ChocolateBoiler();
}
return uniqueInstance;
}
// 其他代码一致
}
前两种方式都采用了延迟实例化,如果程序总是创建并使用该单例对象,或者创建和运行该单例对象时负担不重,可以采用静态初始化器创建单例对象
之所以能使用该方法是因为
JVM
可以保证任何线程访问uniqueInstance
静态变量前一定会创建该单例对象
public class ChocolateBoiler{
// 在静态初始化器创建单例对象
private static ChocolateBoiler uniqueInstance = new ChocolateBoiler();
public static ChocolateBoiler getInstance(){
return uniqueInstance;
}
// 其他代码一致
}
先检查是否创建了实例,如果未创建再进行同步,该方法的是否必须保证再
Java5
以上的版本
public class ChocolateBoiler{
// 在静态初始化器创建单例对象
private volatile static ChocolateBoiler uniqueInstance; // 这里需要使用volatile关键字
public static ChocolateBoiler getInstance(){
if(uniqueInstance = null){
synchronized(ChocolateBoiler.class){
if(uniqueInstance = null){
uniqueInstance = new ChocolateBoiler();
}
}
}
return uniqueInstance;
}
// 其他代码一致
}