1.单例模式 是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
一、单例模式的结构
单例模式的主要有以下角色
- 单例类。只能创建一个实例的类
- 访问类。使用单例类
二、单例模式的实现
单例设计模式分类两种:
饿汉式:类加载就会导致该单实例对象被创建
懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建
1.饿汉式-方式1 (静态变量方式)
package com.jmj.pattern.singleton.demo02;/*** 饿汉式 :静态代码块*/
public class Singleton {private Singleton(){}//声明Singleton类型的变量private static Singleton singleton ;//在静态代码块中进行复制static {singleton=new Singleton();}public static Singleton getInstance(){return singleton;}}
package com.jmj.pattern.singleton.demo01;/*** 饿汉式 :静态成员 变量*/
public class Singleton {//1.私有构造方法private Singleton(){};//2.在本类中创建本类对象private static Singleton singleton =new Singleton();//3.提供一个公共的访问方式,让那个外界获取该对象public static Singleton getInstance(){return singleton;}}
2、懒汉式
线程安全
package com.jmj.pattern.singleton.demo03;/*** 懒汉式 线程不安全*/
public class Singleton {private Singleton(){}private static Singleton singleton;//对外提供访问方式public static synchronized Singleton getInstance(){if (singleton==null){singleton=new Singleton();return singleton;}return singleton;}}
双重检查锁
package com.jmj.pattern.singleton.demo04;/*** 懒汉式 双重检查锁方式*/
public class Singleton {private Singleton(){}private static volatile Singleton singleton;//对外提供访问方式public static Singleton getInstance(){//第一次判断,如果instance的值不为null ,不需要抢占锁,直接返回对象if(singleton==null){synchronized (Singleton.class){if (singleton==null){singleton=new Singleton();}}}return singleton;}}
静态内部类方式
枚举
序列化反序列化破坏单例模式
package com.jmj.pattern.singleton.demo07;import java.io.*;/*** 测试使用反射破坏单例模式*/public class Client {public static void main(String[] args) throws Exception {
// writeObject2File();readObject2File();readObject2File();}//从文件读取数据(对象)public static void readObject2File() throws Exception {ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("src/main/resources/static/a.txt"));Singleton singleton = (Singleton) objectInputStream.readObject();System.out.println(singleton);//释放资源objectInputStream.close();}//向文件中写数据 (对象)public static void writeObject2File() throws Exception {Singleton instance = Singleton.getInstance();ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("src/main/resources/static/a.txt"));objectOutputStream.writeObject(instance);objectOutputStream.close();}}
package com.jmj.pattern.singleton.demo07;import java.io.Serializable;/*** 懒汉式 匿名内部类*/
public class Singleton implements Serializable {private Singleton(){}/*** 静态内部类,只会被 在调用里面属性或者 方法的时候,才会被类加载* 类加载的时候才加载 ,final 修饰 不会被修改*/private static class SingletonHolder{private static Singleton singleton =new Singleton();}//对外提供访问方式public static Singleton getInstance(){return SingletonHolder.singleton;}}
反射破坏单例模式
package com.jmj.pattern.singleton.demo08;import java.io.Serializable;/*** 懒汉式 匿名内部类*/
public class Singleton {private Singleton(){}/*** 静态内部类,只会被 在调用里面属性或者 方法的时候,才会被类加载* 类加载的时候才加载 ,final 修饰 不会被修改*/private static class SingletonHolder{private static Singleton singleton =new Singleton();}//对外提供访问方式public static Singleton getInstance(){return SingletonHolder.singleton;}}
package com.jmj.pattern.singleton.demo08;import java.lang.reflect.Constructor;/*** 测试使用反射破坏单例模式*/public class Client {public static void main(String[] args) throws Exception {//1.获取Singleton的字节码对象Class<Singleton> singletonClass = Singleton.class;Constructor<Singleton> declaredConstructor = singletonClass.getDeclaredConstructor(null);declaredConstructor.setAccessible(true);Singleton singleton = declaredConstructor.newInstance(null);Singleton singleton1 = declaredConstructor.newInstance(null);Singleton singleton2 = declaredConstructor.newInstance(null);System.out.println(singleton);System.out.println(singleton1);System.out.println(singleton2);}}
序列化反序列化破坏单例模式解决方案
package com.jmj.pattern.singleton.demo07;import java.io.Serializable;/*** 懒汉式 匿名内部类*/
public class Singleton implements Serializable {private Singleton(){}/*** 静态内部类,只会被 在调用里面属性或者 方法的时候,才会被类加载* 类加载的时候才加载 ,final 修饰 不会被修改*/private static class SingletonHolder{private static Singleton singleton =new Singleton();}//对外提供访问方式public static Singleton getInstance(){return SingletonHolder.singleton;}public Object readResolve(){return SingletonHolder.singleton;}}
反射破解单例模式解决方案:
首先加个静态变量做标志位,然后 在构造里加锁,锁字节码对象,构造方法就被 加了同步锁了
Runtime 源码就是饿汉式单例模式
package com.jmj.pattern.singleton.demo09;import java.io.IOException;
import java.io.InputStream;public class RuntimeDemo {public static void main(String[] args) throws IOException {Runtime runtime = Runtime.getRuntime();long l = runtime.freeMemory();System.out.println(l);//要的是一个命令Process exec = runtime.exec("ipconfig");//调用process对象InputStream inputStream = exec.getInputStream();byte[] bytes = new byte[1024 * 1024 * 1024];int len = inputStream.read(bytes);String s = new String(bytes,0,len,"GBK");System.out.println(s);}
}
它的作用可以使用Java操作操作系统