一、单例模式
1、饿汉式
/**
* 饿汉式单例模式
*/
public class Singleton implements Serializable{
//饿汉式 直接创建
private static Singleton singleton = new Singleton();
//构造器私有
private Singleton(){
}
//提供一个静态方法来获取单例实例
public static Singleton getInstance(){
return singleton;
}
}
2、懒汉式
/**
* 懒汉式单例模式
*/
public class LazySingleton implements Serializable{
//懒汉式
private static LazySingleton singleton = null;
//构造器私有
private LazySingleton(){
}
//提供一个静态方法来获取单例实例 先查看实例是否为null 如果为null 先创建,有的话直接返回
public static LazySingleton getInstance(){
if(singleton == null){
singleton = new LazySingleton();
}
return singleton;
}
}
二、单例模式改进
1、缺点
上面的两种单例模式,饿汉式是没有线程安全的(存在资源占用),但是懒汉式在多线程环境中,可以会出现多个实例的情况出现,这就违背了单例的规则
2、双重加锁机制
public class Singleton implement Serializable{
private static Singleton singleton = null;
//构造器私有
private ProjectPoint(){
}
//DCL 双重校验
public static synchronized ProjectPoint getInstance(){
if(singleton == null){
synchronized(ProjectPoint.class){
if (singleton == null){
singleton = new ProjectPoint();
}
}
}
return singleton;
}
}
在类中获取实例使用了同步方法,和同步代码块的形式,在多线程中可以很好的避免了单例模式下获取多实例情况的出现。类似于采取了竞争资源(临界资源的同步)
3、静态内部类
类似于饿汉式,主要是基于JVM加载过程中静态变量只初始化一次且线程安全。
public class StaticSingleton implements Serializable{
//构造器私有
private StaticSingleton(){
}
public static synchronized StaticSingleton getInstance(){
return SingetonHolder.staticSingleton;
}
//使用静态内部类来获取实例
/**
* 这个实现思路中最主要的一点就是利用类中静态变量的唯一性
*/
private static class SingetonHolder{
private static final StaticSingleton staticSingleton = new StaticSingleton();
}
}
}
三、单例模式和序列化
单例模式可能在序列化的形式下被破坏,序列化的其实会调用该对象的无参构造器,创建一个新的对象,单例对象的序列化应用场景(数据传输场景不必多说),微服务场景下的远程方法调用RMI。
代码如下:
@Test
public void testSignton(){
StaticSingleton singleton = StaticSingleton.getInstance();
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\xieqixiu\\Desktop\\set.obj"))) {
//对象序列化
oos.writeObject(singleton);
} catch (IOException e) {
e.printStackTrace();
}
StaticSingleton singleton2 = null;
//对象的反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\xieqixiu\\Desktop\\set.obj"))) {
singleton2 = (StaticSingleton) ois.readObject();
//打印出来发现序列化的对象 和原来的对象不是同一个对象违背了单例模式唯一实例
log.info( "projectPoint==projectPoint2 : {}",singleton==singleton2);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
ois.readObject() 方法
public final Object readObject()
throws IOException, ClassNotFoundException
{
if (enableOverride) {
return readObjectOverride();
}
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
//执行该方法获取对象
Object obj = readObject0(false);
}
}
readObject0(false) 方法
/**
* Underlying readObject implementation.
*/
private Object readObject0(boolean unshared) throws IOException {
//省略部分代码
depth++;
totalObjectRefs++;
try {
switch (tc) {
case TC_ENUM:
return checkResolve(readEnum(unshared));
//执行该方法
case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));
//省略部分代码
}
checkResolve()方法
private Object readOrdinaryObject(boolean unshared)
throws IOException
{
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}
ObjectStreamClass desc = readClassDesc(false);
desc.checkDeserialize();
Class<?> cl = desc.forClass();
if (cl == String.class || cl == Class.class
|| cl == ObjectStreamClass.class) {
throw new InvalidClassException("invalid class descriptor");
}
Object obj;
try {
//判断对象是否可以实例化,如果可以调用其中的无参构造器创建该对象实例
obj = desc.isInstantiable() ? desc.newInstance() : null;
} catch (Exception ex) {
throw (IOException) new InvalidClassException(
desc.forClass().getName(),
"unable to create instance").initCause(ex);
}
passHandle = handles.assign(unshared ? unsharedMarker : obj);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}
if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
}
handles.finish(passHandle);
if (obj != null &&
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod())
{
//调用该对象的实现的readResolve()方法 如果有的化
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
rep = cloneArray(rep);
}
if (rep != obj) {
// Filter the replacement object
if (rep != null) {
if (rep.getClass().isArray()) {
filterCheck(rep.getClass(), Array.getLength(rep));
} else {
filterCheck(rep.getClass(), -1);
}
}
handles.setObject(passHandle, obj = rep);
}
}
return obj;
}
在readOrdinaryObject方法中由于调用了obj.newInstance() 会重新创建一个对象, 为了避免这种情况有一个invokeReadResolve()方法(该方法需要序列化的对象编写readResolve() 在该方法下重新返回这个对象信息即可保持序列化和反序列化的实例唯一)
最终代码如下:
//所有单例类 添加该方法
private Object readResolve() {
return singleton;
}