一 单例模式适用场景如下:
在 加载配置文件,线程池,缓存,日志等情况下只需要实例化对象一次
a:代码示例如下(饿汉模式):
package com.dong.singleton;
//单例模式demo练习
/**
*
* @author Administrator
* 单例模式适用的场景如下:
* 在 加载配置文件,线程池,缓存,日志等情况下只需要实例化对象一次
*/
public class Singleton {
private Singleton(){
}
// ctrl + / 单行注视快捷键
// ctrl + shift + / 多行注视快捷键 ctrl + shift + \ 取消多行注视快捷键
//定义一个static 变量存放实例化的对象 ,该方式被称作是汉模式
private static Singleton instance = new Singleton();
// 定义一个静态方法,类不用实例 可直接访问,来访问被封装的一个变量
public static Singleton getInstance(){
return instance;
}
}
b:代码示例如下(懒汉模式):
public class Singleton2 {
// 私有化构造方法,不允许之创建类对象
private Singleton2(){
}
// 创建一个静态私有变量存储实例化的对象
private static Singleton2 instance;
// 创建一个方法能够能够被调用生成对象
public static Singleton2 getInstance(){
// 下面所加代码区别于饿汉模式的区别
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}
二饿汉模式与懒汉模式的区别
饿汉与懒汉的区别如下:
饿汉模式在类的加载的时候,内存已经分配好,加载时候慢,运行时快,并且线程安全
懒汉模式在运行的时候,加载的时候很快,运行的时候很慢,并且线程不安全
针对线程不安全的理由如下:这里讲的线程不安全,主要是在判断是否创建了这个实例的代码块里。
(线程不安全是因为,没有在懒汉模式那里加一个同步块,而且没有加同步块和再加一个判断的话,
这里的懒汉模式并不是真正意义上的单例模式),提到的方法叫双重检查锁定。
问题根源是,instance = new Instance()可以分解成三行伪代码。
正常的顺序是分配对象的内存空间->初始化对象->设置instance指向刚分配的内存地址。
注意第2.3步会被重排序。这时候instance被分配了内存但是没有初始化。
如果这时候有一个线程B来访问,他判断instance!=null后调用这个对象时发现对象没有初始化,
就出现bug了~解决方案:1、Instance声明为volatile类型。2、允许重排序,
但是重排序不被其他线程看到。