单例设计模式的用处。
单例设计模式是指,某个类只有一个实例。在计算机系统中类似于打印机和最常见的就是任务管理器的对话框,不管几个用户同时登录windows 打开的任务对话框只有一个。
常见的几种实现方式:
1.lazy-load
/* 适合单线程模式 延迟加载 lazy-load*/
public class Singleton {
/* 私有的静态对象变量,来标记是否初始化过 也用来把实例化进行缓存*/
private static Singleton instance = null;
/* 私有的构造函数防止外部调用 */
private Singleton (){}
/* 供外部调用的接口是public的其余均为private */
public static Singleton getInstance(){
/* 单线程模式先如果对象变量为空,那么需要创建 */
/* 但是多线程下这个地方需要同步,否则会出现两个线程都创建了一个实例的情况 */
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
2.lazy-load的变种1线程安全了但是效率很差
/* 多线程下可以使用但是如果两个线程同时想创建实例的化,加锁和等待锁是很耗时的
如果不想创建实例了但是还要获取锁,这样很不好。 lazy-load */
public class Singleton{
private static Singleton instance = null;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
3,lazy-load的变种2线程安全了,效率有提高
/* 对上一种方式进行了优化,提前判断一下变量是否为空,前后两次判断是否存在 lazy-load */
/* 但是这种两次if判断的存在出错的情况 */
/* */
public class Singleton{
/* 此处使用volatile关键字 */
private volatile static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
/* 第一次判断 隔绝在已经实例之后调用get接口获取实例对象的情况,放置这些情况仍然调用锁 */
if(instance == null){
/* 防止两个线程同时进行创建实例 */
synchronized(Singleton.class){
/* 这个if判断也是必须的,如果出现了两个线程同时等待锁,但是第一个线程释放之后,第二个线程进入但是却没有判断锁是否释放的化,那么仍然是创建了两次,同时这个instance也一定是volatile 的保证可见性 */
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
但是这样的doubleif仍然有问题。虽然使用了volatile 虽然两次if判断。
因为无序写入:
这个double if 判断的参考了这个写的特别好,值得学习
引申:
4.饿汉式
/* 饿汉式,类加载就会创建实例而不去管你用不用, 但是内存使用率低 线程安全。因为虚拟机保证了类只会加载一次,在装载类的时候是不会并发的 */
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
5.静态内部类
/* 静态内部类 */
/* 由于内部类不会在加载外部类的时候进行加载,那么这个也属于lazy-load。但是这种延迟加载的加载也是class的加载jvm保证只有一次所以同样线程安全 */
public class Singleton{
private Singleton(){}
private static class SingletonIneerClass{
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonIneerClass.instance();
}
}