1.饿汉式
在初始化的时候就实例了一个对象。特点:只会创建一次,所以用不用就是用户的事了,所以对应的缺点也就来了,因为一个类中可能存在多个属性,并且该类在后续的代码中没用被使用过,就会造成内存上的浪费。
案例代码
public class Hungry {
private byte[] data1 = new byte[1024 * 1024];
private byte[] data2 = new byte[1024 * 1024];
private byte[] data3 = new byte[1024 * 1024];
private byte[] data4 = new byte[1024 * 1024];
private Hungry(){}//private的权限是防止构造器访问它而产生新的实例对象
private final static Hungry HUNGRY = new Hungry();
public static Hungry getinstance(){
return HUNGRY;
}
}
2.懒汉式方法
特点: 只有在用户要使用该类是类的内部才会去实例化该类,防止内存的浪费,缺点: 在使用多线程是会发生线程冲突。解决方案:进行加锁。
加完锁后就式双重检查锁的懒汉式单例了, 简称DCL懒汉式(还存在的问题是 : 指令重排),指令重排的解决方案是:为属性添加 volative,volative的作用是: 确保本条指令不会因编译器的优化而省略,且要求每次直接读值, 避免指令重排。
此时该设计模式是不安全的,因为用户可以通过反射中的setAccessible(true)破坏构造方法的私有性,获取空参的构造方法,从而破坏了该模式为了提高安全性,我们还可以在私有的构造方法中添加一个判断。
很多读者可能认为做到这步已经够安全了,确实够安全了,但是如果我每次创建但是同过放射创建的呢?这样会导致通过反射每次都去调用空参的构造函数从而每次都去实例化一个对象,似乎我们的安全性还是不够,所以我们就可以添加一个标记变量解决冲突。
如果我们通过反射获取了标记变量时,似乎安全性又被破坏了。
案例代码
public class LazyMan {
boolean flag = false;
private LazyMan(){//private的权限是防止构造器访问它而产生新的实例对象
if(false){
throw new RuntimeException("别想用放射破坏该模式");
}else{
//通过flag 来记录是否实例化过
flag = true;//表示已被实例化了
}
}
private volatile static LazyMan lazyman;
private static LazyMan getintance(){
if(lazyman == null){
synchronized (LazyMan.class){
//上完锁后再判断一次
if(lazyman == null){
lazyman = new LazyMan();//不是原子性操作
/**
* new过程的步骤为下:
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把对象指向这个空间
*/
}
}
}
return lazyman;
}
// public static void main(String[] args) {
// for(int i = 0; i < 10; i++){
// new Thread(()->{
// LazyMan.getintance();
// });
// }
// }
}
总结
再强的加密,也是会被解密的。正所谓道高一尺魔高一丈。