2.设计模式–创建者模式–单例设计模式
一个程序整个运行过程中,该实例的对象只被创建一次。
2.1单例设计模式的分类:
饿汉式:类加载时创建单例类的对象
懒汉式:类加载时不创建单例类的对象,第一次访问时创建单例类的对象。
2.2单例设计模式
2.2.1饿汉式(静态变量)
/**
* 饿汉式:静态变量创建类的对象
*/
public class Singleton {
//构造方法私有
private Singleton(){}
//静态变量创建类的对象
private static Singleton instance = new Singleton();
//对外提供静态方法
public static Singleton getInstance(){
return instance;
}
}
如果对象不创建会导致内存浪费。
2.2.2 饿汉式(静态代码块)
/**
* 饿汉:静态代码块
*/
public class Singleton2 {
//构造方法私有
private Singleton2(){}
private static Singleton2 instance;
//静态代码块
static{
instance = new Singleton2();
}
//对外提供静态对象获取该对象
public static Singleton2 getInstance(){
return instance;
}
}
如果对象不创建会导致内存浪费。
2.2.3 懒汉式(方式一)
/**
* 懒汉式
*/
public class Singleton3 {
/**
* 构造方法私有
*/
private Singleton3(){};
//在成员位置创建该类的对象
private static Singleton3 instance;
/**
* 静态获取方法
* @return
*/
public static Singleton3 getInstance(){
if(instance==null){
instance = new Singleton3();
}
return instance;
}
}
多线程环境,会出现线程安全问题。
2.2.4 懒汉式(方法上synchronized锁)
public class Singleton4 {
//私有构造方法
private Singleton4(){};
//在成员位置创建该类的对象
private static Singleton4 instance;
/**
* 提供静态方法获取变量
*/
public synchronized static Singleton4 getinstance(){
if(instance==null){
instance = new Singleton4();
}
return instance;
}
}
在初始化instance的时候才会出现线程安全问题,一旦初始化完成就不存在了。
2.2.4 懒汉式(双重检查锁)
public class Singleton5 {
private Singleton5(){};
private static Singleton5 instance;
public static Singleton5 getInstance(){
if(instance==null){
//第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实例
synchronized (Singleton5.class){
//抢到锁之后再次判断是否为null
if(instance==null){
instance = new Singleton5();
}
}
}
return null;
}
}
在多线程的情况下,可能会出现空指针问题,出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作
2.2.5懒汉式(volatile关键字)
public class Singleton6 {
private Singleton6(){};
//volatile参数存在,不会指令重排序
private static volatile Singleton6 instance;
public static Singleton6 getInstance(){
if(instance==null){
//第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实例
synchronized (Singleton6.class){
//抢到锁之后再次判断是否为null
if(instance==null){
instance = new Singleton6();
}
}
}
return null;
}
}
2.2.6懒汉式(静态内部类方式)
public class Singleton7 {
//私有方法构造
private Singleton7(){};
private static class singletonHolder{
private static final Singleton7 INSTANCE = new Singleton7();
}
public static Singleton7 getInstance(){
return singletonHolder.INSTANCE;
}
}
静态属性由于被 static修饰,保证只被实例化一次,并且严格保证实例化顺序
3.1破坏单例模式
1.序列化和反序列化
public class SingletonDemo {
public static void main(String[] args) throws Exception {
//往文件中写对象
writeObject2File();
//从文件中读取对象
Singleton s1 = readObjectFromFile();
Singleton s2 = readObjectFromFile();
//判断两个反序列化后的对象是否是同一个对象
System.out.println(s1 == s2);
}
private static Singleton readObjectFromFile() throws Exception {
//创建对象输入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\a.txt"));
//第一个读取Singleton对象
Singleton instance = (Singleton) ois.readObject();
return instance;
}
public static void writeObject2File() throws Exception {
//获取Singleton类的对象
Singleton instance = Singleton.getInstance();
//创建对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\a.txt"));
//将instance对象写出到文件中
oos.writeObject(instance);
}
}
2.反射
public class Test {
public static void main(String[] args) throws Exception {
//获取Singleton类的字节码对象
Class clazz = Singleton.class;
//获取Singleton类的私有无参构造方法对象
Constructor constructor = clazz.getDeclaredConstructor();
//取消访问检查
constructor.setAccessible(true);
//创建Singleton类的对象s1
Singleton s1 = (Singleton) constructor.newInstance();
//创建Singleton类的对象s2
Singleton s2 = (Singleton) constructor.newInstance();
//判断通过反射创建的两个Singleton对象是否是同一个对象
System.out.println(s1 == s2);
}
}