java的单例模式小知识点

单例模式

目的

为了让一个类有且仅有一个实例

优点

  1. 只允许一个,节省空间

  2. 不用频繁创建删除,提高性能

缺点

  1. 不容易扩展
  2. 长期不使用会被系统当作垃圾回收,造成系统状态的丢失

实现

要点

  1. 防止外界随意的创建对象=》一个私有的构造函数
  2. 保证只有一个实例 =》在私有静态属性中进行声明(饿汉创建,懒汉声明)
  3. 提供这个实例 =》提供静态的公有方法创建和获取私有对象

代码

问题

//会不会报错?
public class test {
    public static void main(String[] args) {
        Sun sun1=new Sun();
    }
}
class Sun{
    Sun sun=new Sun();//它会一直创建Sun对象,解决:用static修饰
}

//运行结果
//Exception in thread "main" java.lang.StackOverflowError
//	at com.imooc.Sun.<init>(test.java:10).....

为什么会报StackOverflowError异常?

图片解释:
第4行开始在栈内存中声明一个叫s的sun对象,并指向堆内存中地址为“0xA”的Sun对象,此时地址“OxA“的Sun对象中有一个实例化本类的属性,所以它又指向地址”0xB” 的Sun对象,此时地址”0xB” 中有一个Sun类型的属性……所以会一直创建Sun对象,出现栈溢出

饿汉式

//饿汉式
public class SingletonTwo {
    //私有构造函数
    private SingletonTwo(){ 
    }
    /**私有静态属性
    	为什么加static,假设不加static,就不能保证只有一个实例,可能会出现上面的问题
    	为什么加private,假设不加private,外界就可以用SingletonTwo.instance=null,把你对象置为空,有危险
    */
    private static SingletonTwo instance=new SingletonTwo();
	/**公共返回
		为什么加static,不加static访问该方法的话需要进行实例化,但是该类已经把构造方法私有化,没办法实例,所以只能用static通过“类名.方法名()”调用
    */
    public static SingletonTwo getInstance(){
        return instance;
    }
}

每次调用前就实例化好了,空间换时间,提前加载以后调用更快

懒汉式

//懒汉式
public class SingletonOne {
    private SingletonOne(){

    }
    private static SingletonOne instance=null;

    public static SingletonOne getSingletonInstance(){
        if (instance==null)//一定要判断
            instance= new SingletonOne();
        return instance;
    }
}

只有每次调用的时候才会实例化,时间换空间,但是当多线程同时访问这个方法时,会存在危险

比如有线程thread1和thread2,thread1第一次运行到第9行,满足条件正准备向下执行时,thread2抢到了执行权限,thread2直接调用getSingletonInstance方法创建了一个SingletonOne对象,thread2执行完后,thread1继续刚才的执行,从第10行开始,最后又创建了一个SingletonOne对象,此时就不满足只创建一个实例的条件了
 解决:给getSingletonInstance()方法加锁

使用场景

  1. 对系统内资源同意读写的,配置文件,如mysql的名字,数据库名,账号密码
  2. 创建对象资源过多