在实际开发中我们会遇到设计模式:也就是程序员的棋谱,遇到类似的问题运用类似的解决方案。
单例模式也就是单个对象,约定某个一个类只能创建一次对象,避免了在new出多个对象的时候内存爆满的情况。(通过现有的语法结构来进行强制检查)。
单例模式也分为懒汉模式和饿汉模式。
1.饿汉模式
饿汉模式实际上就是在类加载的时候就创建好了new的对象,实际上只提供了得到instance的方法。
class Mysingleton{
private static Mysingleton instance=new Mysingleton();
public static Mysingleton getInstance() {
return instance;
}
private Mysingleton(){
}
}
2.懒汉模式
懒汉模式实际上是在第一次调用的时候才new出对象,这里将优化好的直接写出来了。
class Mysingletonal{
//编译器有时候会对程序进行优化,如果不想要优化可以加上volatile。注释一
private static volatile Mysingletonal instance=null;
public static Mysingletonal getInstance(){
//但是每一次重复的加锁又非常麻烦实际上不需要,只需要第一次拿到两个为null进行枷锁i就行了。注释二
if (instance==null) {
synchronized (Mysingletonal.class) {//假如有两个线程第一次拿到都为null,但是 需要对同时拿到的进行加锁。。注释三
if (instance == null) {
instance = new Mysingletonal();
}
}
}
return instance;
}
private Mysingletonal(){
}
}
解释一下三个注释
注释一:
在我们写代码的时候编译器常常会帮我们经行优化,像这里就有指令重排序的优化,当我们new 一个对象的时候实际上做了三件事
1.在内存上面申请一块空间
2.使内存空间上面的地址指向我们的instance对象
3.在内存空间上面初始化也就是调用我们的构造方法
然而2和3有时候编译器会调换顺序,如果我们指向了instance对象后但是没有初始化,这样就会发生问题,好像我们instance对象不为空但是别人调用的确实没有初始化的instance。
注释二:
如果我们每一次调用的时候都要进行加锁和解锁操作的话就会降低系统的高效性,然而实际上只有第一次创建对象的时候需要进行加锁,其余加锁了也是浪费系统资源。
注释三:
第三个地方就是假设有两个线程同时调用创建了一个new对象,为了防止产生线程冲突,我们就要进行加锁。