官方网站下载水印相机南宁seo外包平台
2020-02-23-单例模式(Template Method ):
一、把我能想到的写下来:
单例模式是要实现 对于一个类,只有一个实例化对象,并且有全局??点。
(答:全局的访问点。和全局变量一样方便,但又没有全局变量的缺点:在程序一开始就会创建对象,万一创建对象非常耗费资源,而程序在后面的执行过程中又没有用到它,就形成了浪费。)
对于类的静态属性:当类被加载时,该属性只能被一个线程加载一次。将那个单例的对象 instance 设置为 static,就可以保证**即使多线程访问,也只会初始化一次,只会有一个实例化对象。**然后提供 getInstance 方法,就可以提通过类名直接调用。
public class Singleton {private static Singleton instance=new Singleton();public static Singleton getInstance()return instance;}
(补:这个是 “急切”创建实例,而不是延迟实例化的做法)
(延迟创建:这样 instance 虽然仍是静态属性,但是类加载时,初始化它为 null ,如果需要实例就调用 Singleton 类的 getInstance 方法,先判断 if(instance 是否为空 null,如果为空,就用构造器产生一个 Singleton 实例,如果不为 null ,就表示之前已经创建过对象。
这样可以保证:如果我们不需要这个实例,它就永远不会产生,即——在需要时才创建对象。)
先判断是否初始化过:
public class Singleton {private static Singleton instance;public static Singleton getInstance(){if(instance==null) instance=new Singleton();return instance;}
}
但是这样遇到多线程并发就会出现安全问题:
为了解决安全问题,可以用 synchronized 修饰方法,但 synchronized 会带来性能开销,其实创建单例的步骤同步即可,返回单例对象是不需要同步的,可以使用 volatile synchronized 实现 double-locked 单例模式:
public class DoublieCheckSingleton {private volatile staticDoublieCheckSingleton instance=null;public static DoublieCheckSingleton getInstance(){if(instance==null)//如果未被创建实例,使用 synchronizedsynchronized (DoublieCheckSingleton.class){//再进行一次检查,保证只产生一个实例if(instance==null)instance=new DoublieCheckSingleton();}return instance;}}
以上是把单例对象设置为 static 属性,那么,随着该类被加载,这个单例对象会被初始化,如果我们希望——需要使用到这个实例化对象时才实例化,怎么办呢:延迟加载 lazy load:
不能使用静态属性,就用静态内部类,在静态内部类中写个静态属性:
public class LazyLoadedSingleton {//静态内部类private static class LazyLoader{//在这个静态内部类中,//有个 static 静态属性
private static final LazyLoadedSingleton singleInstance=new LazyLoadedSingleton();}//第一次调用 getInstance 方法时,才会加载 LazyLoader 类public static LazyLoadedSingleton getInstance(){return LazyLoader.singleInstance;}}调用 LazyLoadedSingleton.getInstance() 即可生成单例。
( 补:这也是个 线程安全的 延迟加载。
因为 singleInstance 这个静态属性只会在静态内部类 LazyLoader 被加载时初始化一次,所以是线程安全的。
因为 如果只是加载 LazyLoader 类,而不调用 getInstance() 方法,是不会加载其静态内部类的,更不会初始化 静态内部类的静态属性 singleInstance ,只有当调用 getInstance() 方法 时,才会… … 生成单例,所以是延迟加载。)
二、补充
单例模式:一个类最多只能有一个实例,并提供全局访问点。
有一些对象我们只需要一个,比如说:线程池、缓存、对话框、注册表对象、日志对象等,如果创造出很多实例。就会导致许多问题产生,比如:程序的行为异常、资源使用过量、或者是不一致的结果。
三、思路(超有用)
注意:
♥双重检验要会写。就是 第一次检验是否为 null 之后,用 synchronized ,再次检验 ,如果确实是 null ,才 new 一个实例。
延迟加载也要会写。两个“静” 静态内部类(这样加载类也不会加载静态内部类),静态属性——Instance。♥