设计模式-单例模式的几种实现方式
- PS: 若文章字体偏大或者偏小,建议通过 ctrl键+鼠标滑轮 进行修改,以提升阅读效果.(带来不便,请谅解!)
懒汉式:
1. 线程不安全:
//是否 Lazy 初始化:是
//是否多线程安全:否
//实现难度:易
public class Singleton{
private static final Singleton SINGLETON =new Singleton() ;
public Singleton getInSingleton(){
return SINGLETON;
}
}
饿汉式:
双重锁校验(Double check lock) 实现
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
// Works with acquire/release semantics for volatile
// Broken under current semantics for volatile
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
两个问题
单例模式为什么要加static关键字?
static :
public class SingletonLazy {
//使用volatile 原因如下:
// 避免指令重排序
private volatile SingletonLazy instance = null;
SingletonLazy() {
// jvm执行顺序:
// 1. 分配内存空间
// 2. init, 数据初始化
// 3. 为对象指向分配的内存空间
}
public SingletonLazy getInstance() {
if (instance == null) {
synchronized(SingletonLazy.class){ // 锁住 singletonLazy ,
// synchronized (this) {// 锁this, 即使添加了static 关键字后依旧会出错,
if (instance == null) {
instance = new SingletonLazy();
}
}
}
return instance;
}
}
测试类:
public class Main {
public static void main(String[] args) {
for(int i= 0 ; i<100;i++){
new Thread(()->{
printInstanceDetail();
},"thread"+i).start();
}
}
private static void printInstanceDetail() {
String name = Thread.currentThread().getName();
SingletonLazy inSingleton = new SingletonLazy().getInstance();
System.out.println(name+": "+inSingleton);
}
}
结果示图: (锁this 指针, 不加static 关键字 )
"-javaagent:C:\IntelliJ IDEA 2019.1.3\lib\idea_rt.jar//省略.... thread6: design_patten.singleton.SingletonLazy@76ee89dd thread8: design_patten.singleton.SingletonLazy@168193e5 thread9: design_patten.singleton.SingletonLazy@37cb6108 thread10: design_patten.singleton.SingletonLazy@4025fef1 thread11: design_patten.singleton.SingletonLazy@589c11d1 thread12: design_patten.singleton.SingletonLazy@1468ed9c Process finished with exit code 0
第一次测试:添加static 关键字后 : (锁this,加static 关键字)
thread2: design_patten.singleton.SingletonLazy@278e4dc4
thread5: design_patten.singleton.SingletonLazy@278e4dc4
thread4: design_patten.singleton.SingletonLazy@278e4dc4
thread6: design_patten.singleton.SingletonLazy@278e4dc4
thread1: design_patten.singleton.SingletonLazy@6223c513
第二次测试: 锁 类对象SingletonLazy.class ,加 static 关键字
thread5: design_patten.singleton.SingletonLazy@76ee89dd
thread3: design_patten.singleton.SingletonLazy@76ee89dd
thread4: design_patten.singleton.SingletonLazy@76ee89dd
thread7: design_patten.singleton.SingletonLazy@76ee89dd
thread6: design_patten.singleton.SingletonLazy@76ee89dd
thread2: design_patten.singleton.SingletonLazy@76ee89dd
thread0: design_patten.singleton.SingletonLazy@76ee89dd
thread8: design_patten.singleton.SingletonLazy@76ee89dd
thread1: design_patten.singleton.SingletonLazy@76ee89dd
thread9: design_patten.singleton.SingletonLazy@76ee89dd
单例模式为什么要用final 关键字?
final修饰的变量值不会改变。
但是在多线程的环境中,它还会保证两点,
**1. 其他线程所看到的final字段必然是初始化完毕的。 **
2. final修饰的变量不会被程序重排序。
声明为final的变量,必须在类加载完成时已经赋值, 是什么意思呢?
就是,如果你是final非static成员,必须在构造器、代码块、或者直接定义赋值;
如果是final static 成员变量,必须直接赋值 或者在 静态代码块中赋值。
然而直接赋值 或 静态代码块中赋值 就变成饿汉模式了,
所以懒汉模式中,不能用final修饰
总结:
参考:
猜你喜欢