单例模式
饿汉式 在类加载时就会创建对象
静态变量方式
public class Singleton {
//1.私有构造方法
private Singleton(){}
//2.在本类中创建本类对象
private static Singleton instance = new Singleton();
//3.提供一个公共的访问方式,让外界获取该对象
public static Singleton getInstance(){
return instance;
}
}
该方式在成员位置声明Singleton类型的静态变量,并创建Singleton类的对象instance,
instance对象是随着类的加载而创建的。如果该对象足够大的话,而一直没有使用就会造成内存泄漏
静态代码块方式
也存在内存浪费的可能
public class Singleton {
//1.私有构造方法
private Singleton(){}
//声明Singleton类型的变量
private static Singleton instance;
//在静态代码块中赋值
static {
instance = new Singleton();
}
//对外提供获取该类对象的方法
public static Singleton getInstance(){
return instance;
}
}
懒汉式:
public class Singleton {
//1.私有构造方法
private Singleton(){}
//声明Singleton类型的变量
private static Singleton instance;
//对外提供获取该类对象的方法
public static Singleton getInstance(){
if(instance == null)
/*线程1执行完判断语句后,失去cpu控制权
线程2判断此时为null,又创建一个实例
* */
instance = new Singleton();
return instance;
}
}
双重检查锁方式
//对外提供获取该类对象的方法
public static synchronized Singleton getInstance(){
//双重检查锁方式
if(instance == null){
synchronized (Singleton.class){
if(instance == null)
instance = new Singleton();
}
}
return instance;
}
静态内部类方式
静态内部类单例模式中实例由内部类创建,由于JA在加载外部类的过程中,是不会加载静态内部类的,只有内部类的属性/方法被调用时才会被加载,并初始化其静态属性。静态属性由于被statie]修饰,保证只被实例化一次,并且严格保证实例化顺序。
public class Singleton {
//私有构造方法
private Singleton(){}
//定义一个静态内容部类
private static class SignletonHolder{
//在内部类声明并初始化外部类的对象
private static final Singleton INSTANCE = new Singleton();
}
//提供公共的访问方式
public static Singleton getInstance(){
return SignletonHolder.INSTANCE;
}
}
测试
public class Client {
public static void main(String[] args) {
//创建Singleton类的对象
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
//判断获取的两个对象是否是同一个对象
System.out.println(instance == instance1);
}
}
枚举方式
枚举类实现单例模式是极力推荐的单例实现模式,因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚举的这个特性来实现单例模式,致举的写法非常简单,而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。
public enum Singleton {
INSTANCE;
}
//测试
public class Client {
public static void main(String[] args) {
//创建Singleton类的对象
Singleton instance = Singleton.INSTANCE;
Singleton instance1 = Singleton.INSTANCE;
System.out.println(instance == instance1);
}
}
存在问题
序列化、反序列化破坏单例模式
public class Client {
public static void main(String[] args) throws IOException, ClassNotFoundException {
writeObject2File();
//观看两次获取的对象地址是否相同
readObjectFromFile();
readObjectFromFile();
}
public static void writeObject2File() throws IOException {
Singleton instance = Singleton.getInstance();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.txt"));
objectOutputStream.writeObject(instance);
objectOutputStream.close();
}
public static void readObjectFromFile() throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.txt"));
Singleton instance = (Singleton)objectInputStream.readObject();
System.out.println(instance);
objectInputStream.close();
}
}
反射破坏单例模式
public class Client {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取Singleton字节码对象
Class clazz = Singleton.class;
//获取无参构造方法对象
Constructor constructor = clazz.getDeclaredConstructor();
//取消访问检查
constructor.setAccessible(true);
Singleton instance = (Singleton)constructor.newInstance();
Singleton instance2 = (Singleton)constructor.newInstance();
System.out.println(instance == instance2);
}
}
JDk源码解析-Runtime类
Runtimo类就是使用的单例设计模式。
1.通过源代码查看使用的是哪儿种单例模式
public class Client {
public static void main(String[] args) throws IOException {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("ipconfig");//参数是一个命令
InputStream inputStream = process.getInputStream();
byte arr[] = new byte[1024*1024*100];
int len = inputStream.read(arr);
System.out.println(new String(arr,0,len,"GBK"));
}
}