单例模式的实现(5种)
常用:
饿汉式(线程安全,调用效率高,但是不能延时加载)
懒汉式(线程安全,调用效率不高,可以延时加载)
其他:
双重检测锁式(由于jvm底层内部模型原因,偶尔会出问题,不建立使用)
静态内部类式(线程安全,调用效率高,但是可以延时加载)
枚举单例(线程安全,调用效率高,不能延时加载)
饿汉式单例具体代码如下:
package com.lcx.mode;
public class SingletonHanger {
private static final SingletonHanger instance = new SingletonHanger();
private SingletonHanger() {
}
public static SingletonHanger getInstance(){
return instance;
}
}
class SingletonLazy{
private static SingletonLazy instance = null;
private SingletonLazy() {
}
public static SingletonLazy getInstance1(){
if(instance==null){
instance = new SingletonLazy();
}
return instance;
}
public static synchronized SingletonLazy getInstance2(){
if(instance==null){
instance = new SingletonLazy();
}
return instance;
}
public static synchronized SingletonLazy getInstance3(){
if(instance==null){
synchronized (SingletonLazy.class) {
if(instance==null){
instance = new SingletonLazy();
}
}
}
return instance;
}
}
enum SingletionEnum{
SingletionEnum("单例的枚举方式");
private String str ;
private SingletionEnum(String str){
this.setStr(str);
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
以上的单例模式就不测试,大家可以去测试,判断对象的hashcode是否一致来判断是否为同一个对象。
恶汉式、懒汉式的方式还不能防止反射来实现多个实例,通过反射的方式,设置ACcessible.setAccessible方法可以调用私有的构造器,可以修改构造器,让它在被要求创建第二个实例的时候抛出异常。
其实这样还不能保证单例,当序列化后,反序列化是还可以创建一个新的实例,在单例类中添加readResolve()方法进行防止。
懒汉汉式单例代码如下:
package com.lcx.mode;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Singleton implements Serializable{
private static final long serialVersionUID = -5271537207137321645L;
private static Singleton instance = null;
private static int i = 1;
private Singleton() {
if(i==1){
i++;
}else{
throw new RuntimeException("只能调用一次构造函数");
}
System.out.println("调用Singleton的私有构造器");
}
public static synchronized Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class) {
if(instance==null){
instance = new Singleton();
}
}
}
return instance;
}
private Object readResolve(){
return instance;
}
public static void main(String[] args) throws Exception {
test1();
test2();
}
public static void test2() throws Exception{
Singleton s = Singleton.getInstance();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("E:\Singleton.txt")));
objectOutputStream.writeObject(s);
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("E:\Singleton.txt")));
Object readObject = objectInputStream.readObject();
Singleton s1 = (Singleton)readObject;
System.out.println("s.hashCode():"+s.hashCode()+",s1.hashCode():"+s1.hashCode());
objectOutputStream.flush();
objectOutputStream.close();
objectInputStream.close();
}
public static void test1(){
Singleton s = Singleton.getInstance();
Class c = Singleton.class;
Constructor privateConstructor;
try {
privateConstructor = c.getDeclaredConstructor();
privateConstructor.setAccessible(true);
privateConstructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
}
验证反射攻击结果:
如果不添加readResolve方法的结果:
添加readResolve方法的结果:
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!



