概念理解
单例模式是最简单的设计模式之一,简单理解就是一个类在整个系统运行环境中只有一个实例。这是一种创建型模式,典型的特点是构造器私有化,然后提供一个静态公共 方法获取实例。创建单例饿汉式(类加载时就创建),懒汉式(第一次使用时创建)。
饿汉式:
实现非常简单,在声明属性中直接创建,这种方式是线程安全的,只是可能会造成空间的浪费(创建了却没有地方使用)。
//非懒加载,线程安全,一般推荐这种方式
public class ChocolateFactory {
private boolean empty;
private boolean boiled;
private static ChocolateFactory INSTANCE = new ChocolateFactory();
private ChocolateFactory() {
this.empty = true;
this.boiled = false;
}
public static ChocolateFactory getInstance(){
return INSTANCE;
}
}
懒汉式:
懒汉式即在第一次使用的时候创建实例,这里提供了一种线程不安全的和三种线程安全的实现方式
public class ChocolateFactory {
private boolean empty;
private boolean boiled;
private static ChocolateFactory INSTANCE = null;
private ChocolateFactory() {
this.empty = true;
this.boiled = false;
}
//线程不安全
public static ChocolateFactory getInstance() {
if (INSTANCE == null) {
INSTANCE = new ChocolateFactory();
}
return INSTANCE;
}
//线程安全
public synchronized static ChocolateFactory getInstanteThreadSec() {
if (INSTANCE == null) {
INSTANCE = new ChocolateFactory();
}
return INSTANCE;
}
}
在方法上加锁,虽然实现了线程安全,但是当线程并发量大的时候,会造成排队浪费时间的现象,因此使用双重锁机制比较好。
public class ChocolateFactory {
private boolean empty;
private boolean boiled;
private volatile static ChocolateFactory INSTANCE= null;
private ChocolateFactory(){
this.empty=true;
this.boiled=false;
}
public static ChocolateFactory getInstante(){
if(INSTANCE==null){
synchronized (ChocolateFactory.class){
if(INSTANCE==null){
INSTANCE = new ChocolateFactory();
}
}
}
return INSTANCE;
}
}
还有一种方式是使用内部类,是基于饿汉式的一种改造
public class ChocolateFactory {
private boolean empty;
private boolean boiled;
private ChocolateFactory() {
this.empty = true;
this.boiled = false;
}
//线程安全且是懒加载的
public static class ChocolateFactoryHolder {
private volatile static ChocolateFactory INSTANCE = new ChocolateFactory();
}
public static ChocolateFactory getInstance() {
return ChocolateFactoryHolder.INSTANCE;
}
}
volatile
volatile一种轻量级的同步机制,一个线程共享变量(静态变量)使用volatile修饰,表示这个变量是内存可见性,即一个线程修改了改变量,会立马通知另外的线程。
实际上,内存共享变量的写入和对另外线程的可见,都是通过java内存模型(JMM)控制的。共享变量存储在主内存中,每个线程都有自己的本地内存,存有使用到的主内存的副本拷贝,线程对变量的操作,都是在本地内存中进行,如果需要及时同步到主内存中,需要volatile关键字修饰。
完整代码实例参见https://github.com/jxl198/designPattern/tree/master/singleton
网友评论