您的位置:首页 > 编程语言 > Java开发

Java单例模式解析

2014-04-23 18:06 369 查看
package singleton;
/**
* 最简单的单例模式
*/
public class SimpleSingleton {

/**
* 构造方法私有化,外部无法通过构造方法创建对象,这样能够屏蔽外部直接new
* 还有就是反射了,反射时可以使用setAccessible方法来突破private的限制,
* 我们需要做到第一点工作的同时,还需要在在ReflectPermission("suppressAccessChecks")
* 权限下使用安全管理器(SecurityManager)的checkPermission方法来限制这种突破,
* 一般来说,不会真的去做这些事情,都是通过应用服务器进行后台配置实现。
* 再就是序列化了,序列化会在SimpleSerializableSingleton这个类中做介绍
*/
private SimpleSingleton(){}

/**
* 类型是static,这样在JVM进行类加载的时候就会做类的实例化,JVM保证线程安全
* 根据JLS(Java Language Specification)中的规定,一个类在一个ClassLoader中只会被初始化一次,
* 这点是JVM本身保证的,那就把初始化实例的事情扔给JVM好了
*/
private static final SimpleSingleton instance = new SimpleSingleton();

//通过一个静态方法,获得这个对象
public static SimpleSingleton getInstance(){
return instance;
}
}

------------------------------------------------------------------------------------------------------

package singleton;
/**
* 单例模式的懒加载策略,不在类加载的时候进行实例化,而是在第一次调用的时候进行
*/
public class SimpleLazySingleton {

//私有构造方法
private SimpleLazySingleton(){}

//在类加载的时候,这个对象不进行实例化,volatile变量,拥有可见性
private static volatile SimpleLazySingleton instance = null;

/**
* @deprecated
* 这种会有线程安全问题,因为可能存在多线程访问这个方法,这个时候对象就有可能不是单例的
*/
public static SimpleLazySingleton getInstanceNotSafe(){
if(instance == null){
instance = new SimpleLazySingleton();
}
return instance;
}

/**
* @deprecated
* 做一个简单的处理,就是在getInstance的时候添加锁关键字
* 但是这样有个问题,就是所有的getInstance操作全部加锁,性能会下降很多
*/
public static synchronized SimpleLazySingleton getInstanceSyncSafe(){
if(instance == null){
instance = new SimpleLazySingleton();
}
return instance;
}

/**
* @deprecated
* 那就做锁的细化吧,把锁的处理挪到方法体内部,仅仅在instance为空的时候,再去加锁
*/
public static SimpleLazySingleton getInstanceSyncNotSafe(){
if(instance == null){
synchronized (SimpleLazySingleton.class) {
instance = new SimpleLazySingleton();
}
}
return instance;
}

/**
* 那就做锁的细化吧,把锁的处理挪到方法体内部,仅仅在instance为空的时候,再去加锁
*/
public static SimpleLazySingleton getInstance(){
if(instance == null){
synchronized (SimpleLazySingleton.class) {
/**
* 这里称之为double-check-lock,为啥要做这不操作呢?
* 因为可能有多个线程进入第一个“if(instance == null)”,这个时候,线程去强占锁,
* 抢到锁的线程进行instance的初始化操作,完了之后释放锁,
* 第二个线程获得锁,这个时候进入之后,如果没有判空操作,会再一次初始化了实例,这时候就不是单例了
*/
if(instance == null){
instance = new SimpleLazySingleton();
}
}
}
return instance;
}
}
------------------------------------------------------------------------------------------------------

package singleton;

/**
* 通过Holder的形式来进行,利用JVM的机制来保障线程安全
*/
public class SimpleHolderSingleton {

//私有化
private SimpleHolderSingleton(){}

//类中有一个私有的XXXHolder类,这个因为是static类型的,所以在JVM加载类的时候就会加载到,但是INSTANCE就不会
private static class SimpleHolderSingletonHolder{
//持有外部类的属性
static final SimpleHolderSingleton INSTANCE = new SimpleHolderSingleton();
}

//这样会在第一次调用的时候进行初始化操作,因为INSTANCE是static的,所以借助了JVM的机制来保障线程安全
public static SimpleHolderSingleton getInstance(){
return SimpleHolderSingletonHolder.INSTANCE;
}
}

------------------------------------------------------------------------------------------------------

package singleton;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
* 如果单例的类实现了序列化接口,这个时候需要做一下特殊处理,
*/
public class SimpleSerializableSingleton implements java.io.Serializable{

private static final long serialVersionUID = -589503673156379879L;

//屏蔽外部new的实例化
private SimpleSerializableSingleton(){}

private static SimpleSerializableSingleton instance = new SimpleSerializableSingleton();

public static SimpleSerializableSingleton getInstance(){
return instance;
}

/**
* 这个方法,会在发序列化构建对象的时候调用到,如果不这么处理
* 反序列化之后的对象,是另外一个内存地址,也就是说不再是单例的了
*/
private Object readResolve() {
System.out.println("readResolve,被调用了");
return getInstance();
}

public static void main(String[] args) throws Exception {
SimpleSerializableSingleton simple = SimpleSerializableSingleton.getInstance();
//获得单例对象的内存地址
System.out.println(simple);
//定义序列化写入的文件
File file = new File("d:\\git\\serializable");
//构造objectOutputStream
ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream(file));
//写入对象
outStream.writeObject(simple);
outStream.close();

//反序列化
ObjectInputStream inStream = new ObjectInputStream(new FileInputStream(file));
SimpleSerializableSingleton simpeFromSeria = (SimpleSerializableSingleton)inStream.readObject();
System.out.println(simpeFromSeria);
inStream.close();
}

}
------------------------------------------------------------------------------------------------------

package singleton;

import java.lang.reflect.ReflectPermission;
import java.security.Permission;
/**
* 如何禁止外部通过反射来做单例对象的序列化
*/
public class SimpleReflectionSingleton {

private SimpleReflectionSingleton(){}

private static SimpleReflectionSingleton instance = new SimpleReflectionSingleton();

public static SimpleReflectionSingleton getInstance(){
return instance;
}
public static void main(String[] args) throws Exception{

//启动JVM的安全检察,在进行反射校验的时候,判断一下是否是“singleton”,如果是,就禁止反射
System.setSecurityManager(new SecurityManager(){
@Override
public void checkPermission(Permission perm) {
if (perm instanceof ReflectPermission && "suppressAccessChecks".equals(perm.getName())) {
for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
if (elem.getClassName().endsWith("Singleton")) {
throw new SecurityException();
}
}
}
}
});

SimpleReflectionSingleton simple = SimpleReflectionSingleton.getInstance();
System.out.println(simple);

Class<?> clazz = SimpleReflectionSingleton.class;

SimpleReflectionSingleton ref = (SimpleReflectionSingleton)clazz.newInstance();

System.out.println(ref);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: