立即加载/饿汉模式
立即加载是指使用类的时候已经将对象创建完毕,常见的实现方法,是直接用new实例化。立即加载有”着急“”迫切“的意思,所以也称为”饿汉模式“
在立即加载中,调用方法前,实例已经被工厂创建了
public class MyObject {
//立即加载方式
private static MyObject myObject = new MyObject();
private MyObject(){
}
public static MyObject getInstance(){
//实例化
return myObject;
}
}
延迟加载/懒汉模式
延迟加载是指调用get()方法时实例才被工厂创建,常见的实现方法是在get()中进行new实例化
public class MyObject {
//立即加载方式
private static MyObject myObject;
private MyObject(){
}
public static MyObject getInstance(){
if (myObject != null){
}else {
myObject = new MyObject();
}
return myObject;
}
}
但是这种情况在多线程环境中会出现取出多个实例的情况,这和单例模式的初衷是违背的
解决方案
- 声明synchronized关键字,但是运行效率非常低
public class MyObject {
//立即加载方式
private static MyObject myObject;
private MyObject() {
}
//设置同步方法
synchronized public static MyObject getInstance() {
try {
if (myObject != null) {
} else {
Thread.sleep(3000);
myObject = new MyObject();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}
- 尝试同步代码块,但是效率还是非常低
public class MyObject {
//立即加载方式
private static MyObject myObject;
private MyObject() {
}
//设置同步方法
public static MyObject getInstance() {
try {
synchronized (MyObject.class) {
if (myObject != null) {
} else {
Thread.sleep(3000);
myObject = new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}
- 针对某些重要代码进行单独同步,效率虽然提高了,但是在多线程的情况下还是无法解决得到同一个实例对象的结果
public class MyObject {
//立即加载方式
private static MyObject myObject;
private MyObject() {
}
//设置同步方法
public static MyObject getInstance() {
try {
if (myObject != null) {
} else {
Thread.sleep(3000);
//部分上锁
synchronized (MyObject.class) {
myObject = new MyObject();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}
- 最最最牛的DCL机制
DCL(Double-Check Locking)双重锁机制
public class MyObject {
//立即加载方式
private volatile static MyObject myObject;
private MyObject() {
}
//设置同步方法
public static MyObject getInstance() {
try {
if (myObject != null) {
} else {
Thread.sleep(3000);
//部分上锁
synchronized (MyObject.class) {
if (myObject == null) {
myObject = new MyObject();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}
通过volatile修改变量myObject使该变量在多个线程间达到可见性,另外也禁止了myObject=new MyObject()代码重排序,因为myObject=new MyObject()的执行顺序为
- 分配空间
- 初始化对象
- 设置instance指向刚分配的内存地址
所以要禁止重排序
DCL是大多数多线程结合单例模式使用的解决方案