【Java】设计模型-五种单例模型
2021-07-08 11:04
标签:线程 syn 管理 vat load effect 构造函数 ack 设计模型 只需要某个类同时保留一个对象,不希望有更多对象,此时,我们则应考虑单例模式的设计。 单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在。 单例模式有很多好处,它能够避免实例对象的重复创建,不仅可以减少每次创建对象的时间开销,还可以节约内存空间; 能够避免由于操作多个实例导致的逻辑错误。如果一个对象有可能贯穿整个应用程序,而且起到了全局统一管理控制的作用,那么单例模式也许是一个值得考虑的选择。 1. 单例模式只能有一个实例。 2. 单例类必须创建自己的唯一实例。 3. 单例类必须向其他对象提供这一实例。 在知道了什么是单例模式后,我想你一定会想到静态类,“既然只使用一个对象,为何不干脆使用静态类?”,这里我会将单例模式和静态类进行一个比较。 1. 单例可以继承和被继承,方法可以被override,而静态方法不可以。 2. 静态方法中产生的对象会在执行后被释放,进而被GC清理,不会一直存在于内存中。 3. 静态类会在第一次运行时初始化,单例模式可以有其他的选择,即可以延迟加载。 4. 基于2, 3条,由于单例对象往往存在于DAO层(例如sessionFactory),如果反复的初始化和释放,则会占用很多资源,而使用单例模式将其常驻于内存可以更加节约资源。 5. 静态方法有更高的访问效率。 6. 单例模式很容易被测试。 误解一:静态方法常驻内存而实例方法不是。 实际上,特殊编写的实例方法可以常驻内存,而静态方法需要不断初始化和释放。 误解二:静态方法在堆(heap)上,实例方法在栈(stack)上。 实际上,都是加载到特殊的不可写的代码内存区域中。 情景一:不需要维持任何状态,仅仅用于全局访问,此时更适合使用静态类。 情景二:需要维持一些特定的状态,此时更适合使用单例模式。 注解:初试化静态的instance创建一次。如果我们在Singleton类里面写一个静态的方法不需要创建实例,它仍然会早早的创建一次实例。而降低内存的使用率。 缺点:没有lazy loading的效果,从而降低内存的使用率。 注解:Singleton的静态属性instance中,只有instance为null的时候才创建一个实例,构造函数私有,确保每次都只创建一个,避免重复创建。 注解:只有当instance为null时,需要获取同步锁,创建一次实例。当实例被创建,则无需试图加锁。 这种方式同样利用了类加载机制来保证只创建一个instance实例。它与饿汉模式一样,也是利用了类加载机制,因此不存在多线程并发的问题。不一样的是,它是在内部类里面去创建对象实例。这样的话,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。也就是说这种方式可以同时保证延迟加载和线程安全。 上面提到的四种实现单例的方式都有共同的缺点: 1)需要额外的工作来实现序列化,否则每次反序列化一个序列化的对象时都会创建一个新的实例。 2)可以使用反射强行调用私有构造器(如果要避免这种情况,可以修改构造器,让它在创建第二个实例的时候抛异常)。 而枚举类很好的解决了这两个问题,使用枚举除了线程安全和防止反射调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象。因此,《Effective Java》作者推荐使用的方法。不过,在实际工作中,很少看见有人这么写。 本文总结了五种Java中实现单例的方法,其中前两种都不够完美,双重校验锁和静态内部类的方式可以解决大部分问题,平时工作中使用的最多的也是这两种方式。枚举方式虽然很完美的解决了各种问题,但是这种写法多少让人感觉有些生疏。个人的建议是,在没有特殊需求的情况下,使用第三种和第四种方式实现单例模式。 【Java】设计模型-五种单例模型 标签:线程 syn 管理 vat load effect 构造函数 ack 设计模型 原文地址:https://www.cnblogs.com/zeze/p/9582377.html一. 什么是单例模式
二. 单例模式的特点
三. 单例模式VS静态类
几个关于静态类的误解:
静态类和单例模式情景的选择:
单例模型的写法
1、饿汉模式
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton newInstance(){
return instance;
}
}
2、懒汉模式
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static Singleton newInstance(){
if(null == instance){
instance = new Singleton();
}
return instance;
}
}
缺点:只在单线程的情况下正常运行,在多线程的情况下,就会出问题。例如:当两个线程同时运行到判断instance是否为空的if语句,并且instance确实没有创建好时,那么两个线程都会创建一个实例,因此需要加锁解决线程同步问题,实现如下:public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static synchronized Singleton newInstance(){
if(null == instance){
instance = new Singleton();
}
return instance;
}
}
3、双重校验锁
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {//2
instance = new Singleton();
}
}
}
return instance;
}
}
缺点:用双重if判断,复杂,容易出错。4、静态内部类
public class Singleton{
private static class SingletonHolder{
public static Singleton instance = new Singleton();
}
private Singleton(){}
public static Singleton newInstance(){
return SingletonHolder.instance;
}
}
5、枚举
public enum Singleton{
instance;
public void whateverMethod(){}
}
总结