You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
解释:getInstance()调用了LazyHolder的静态字段INSTANCE,所以会触发LazyHolder的加载和初始化。LazyHolder的初始化阶段会对静态字段INSTANCE进行赋值,也就是 new Singleton(),此外初始化阶段是线程安全的且只执行一次,因此就算是多线程,也只会创建一个Singleton对象。从而实现单例。
Reacted by Hulk Su, KenStive, 叫我小泡泡_, acer-xhy, ChenLeizheng, LqhlQh, 周豪侠, RedDargon, Kysop, chen3441251 and 2 more
解释:getInstance()调用了LazyHolder的静态字段INSTANCE,所以会触发LazyHolder的加载和初始化。LazyHolder的初始化阶段会对静态字段INSTANCE进行赋值,也就是 new Singleton(),此外初始化阶段是线程安全的且只执行一次,因此就算是多线程,也只会创建一个Singleton对象。从而实现单例。
解释:getInstance()调用了LazyHolder的静态字段INSTANCE,所以会触发LazyHolder的加载和初始化。LazyHolder的初始化阶段会对静态字段INSTANCE进行赋值,也就是 new Singleton(),此外初始化阶段是线程安全的且只执行一次,因此就算是多线程,也只会创建一个Singleton对象。从而实现单例。
解释:getInstance()调用了LazyHolder的静态字段INSTANCE,所以会触发LazyHolder的加载和初始化。LazyHolder的初始化阶段会对静态字段INSTANCE进行赋值,也就是 new Singleton(),此外初始化阶段是线程安全的且只执行一次,因此就算是多线程,也只会创建一个Singleton对象。从而实现单例。
解释:getInstance()调用了LazyHolder的静态字段INSTANCE,所以会触发LazyHolder的加载和初始化。LazyHolder的初始化阶段会对静态字段INSTANCE进行赋值,也就是 new Singleton(),此外初始化阶段是线程安全的且只执行一次,因此就算是多线程,也只会创建一个Singleton对象。从而实现单例。
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
Activity
DaveBoy commentedon Mar 25, 2019
单例模式,主要用于某些环境下对象的唯一性,分为线程安全和不安全,写法也比较多,但是个人认为只要熟悉主要的几种就行,包括双检查、静态内部类、枚举
ADrunkenLiBai commentedon Mar 25, 2019
楼上说的很对,对象重复创建消耗资源很大,单例也仅仅是避免对象重复创建,节省内存,避免多个实例存在线程的不安全,存在多个实例对象,业务逻辑就会复杂很多,至于写法就看业务跟个人喜好了,写法很多,楼上已经说了
manondidi commentedon Mar 25, 2019
单例分为懒汉模式和恶汉模式
懒汉模式有线程安全和非线程安全的区别
实现线程安全的懒汉模式有多重 其中一种是加double check
在代码 在多线程中 两个线程可能同时进入代码2, synchronize保证只有一个线程能进入下面的代码,
此时一个线程A进入一个线程B在外等待, 当线程A完成代码3 和代码4之后,
线程B进入synchronized下面的方法, 线程B在代码3的时候判断不过,从而保证了多线程下 单例模式的线程安全,
另外要慎用单例模式,因为单例模式一旦初始化后 只有进程退出才有可能被回收,如果一个对象不经常被使用,尽量不要使用单例,否则为了几次使用,一直让单例存在占用内存
FeatherHunter commentedon Mar 25, 2019
借助类加载机制,可以在不使用synchronized等内容的情况下,最高效的实现单例。
访问静态字段时,才会会初始化静态字段所在的类类初始化是线程安全的,并且只会执行一次。因此在多线程环境下,依然能保证只有一个Singleton实例。LazyHolder的加载和初始化。LazyHolder的初始化阶段会对静态字段INSTANCE进行赋值,也就是new Singleton(),此外初始化阶段是线程安全的且只执行一次,因此就算是多线程,也只会创建一个Singleton对象。从而实现单例。Ssuiyingsen commentedon Mar 26, 2019
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例 。
其又分为三种形式
饿汉式,懒汉式,双重锁式
zhangyalei1 commentedon Apr 24, 2019
这种也行吗?有没有优缺点,哪位同学呢个讲一下吗
Moosphan commentedon Apr 24, 2019
可以参考一下《Android源码设计模式解析与实战》,里面对于单例的实现方式做了比较详细的讲解。:smile:
scsfwgy commentedon Apr 25, 2019
顺便问一下,无论是单例、多实例、还是静态方法,我们大部分都是在访问”方法“。那么单例和静态方法有什么区别?用单例,我干嘛不把单例里面的方法都定义为静态的,成员变量也定义为静态的?
947635060 commentedon Apr 28, 2019
单例模式,主要用于某些环境下对象的唯一性,分为线程安全和不安全。
上面已经说了
ArtarisCN commentedon Apr 28, 2019
使用
synchronized同步 new 方法,内外加双重判断,volatile 修饰实例。synchronized 能保证每次只有一个线程访问代码块,volatile 保证了 instance 创建的原子性。
优点:简单粗暴,线程安全,高效,自动避免序列化/反序列化攻击、反射攻击(枚举类不能通过反射生成)
缺点:可读性差
scsfwgy commentedon Apr 29, 2019
同样的,定义一个类里面全部用静态方法和静态属性同样可以实现... 如果太局限于“标准答案”,面试官稍微延伸一点就会答不上来。。。
ddssingsong commentedon Apr 30, 2019
其实,了解下单例模式的历史,以及每种单例模式要解决的核心问题,那么这个问题就能串到一起了
来来,继续回答问题三段式
为什么要使用单例
这个问题搞的我很方啊
其实我觉得使用单例完全是场景需要,用不用可以体现一个系统的好不好
单例的发展历程
饿汉式
这个东西是线程安全的,早期代码就这写完全没问题
懒汉式
突然有一天,有人发现,这个单例一直没用过,但是这个东西还是一直占用我的内存,于是就有了下面的代码
双重线程锁
过了一段时间,有人发现在线程中使用懒汉式有问题,对象被创建了多次,为了解决创建多个的问题,就有了synchronized加锁模式,而这个加锁会导致创建变慢,就有了双重检验锁模式,刚开始没啥问题,突然有一天,他们遇到了一个无法重现的问题,Singleton又被创建了多次,程序员方了。
经过了多方努力,最后找到了问题
很长一段时间,我们都是使用这个DCL模式
静态内部类单例
这种单例为何会横空出世,我也很费解,官方的解释是延迟了单例对象的加载时机。
我觉得这种单例会被引用进来有三点原因
枚举类单例
突然有一天,我们有个需求是这样的,我们需要把单例序列化放到文件中去,当我从文件中取出来时,我还想用的是存进去的那个单例
哎呀,这个问题搞得我又方了
这时候,枚举类单例横空出世,你把这个单例序列化下存到文件再取出来试试喽
我们最终选择了那种方式
ddssingsong commentedon Apr 30, 2019
对了,Android系统中还有一种单例模式,叫啥来着,HashMap实现的单例
RedDargon commentedon May 8, 2019
有些实例需要在整个环境中以单例的形式存在,或者多次创建需要耗费很大资源。所以需要设定单例模式来保证他的唯一性。
xianfeng92 commentedon May 17, 2019
synchronized 能保证每次只有一个线程访问代码块,即 instance 实例创建的原子性,volatile 保证了 instance 对多个线程的内存可见性。
run-forrest commentedon May 23, 2019
其实吹毛求疵来说,这种是使用了synchronized,详见ClassLoader 类加载机制,loadClass有使用到synchronized。如果非要说不使用synchronized的话,可以参考下CAS,不过客户端开发我觉得基本没必要。
guaiguai2015 commentedon Jul 23, 2019
https://blog.csdn.net/mnb65482/article/details/80458571
这个链接里很好的说明了一些单例模式的优缺点以及回答了你的问题
pengxurui commentedon Aug 5, 2019
世人都只知道应用级别的单例,如果你能说出线程级别的单例,会加分哦!
1、ThreadLocal可以很方便地实现线程级别单例
2、Map<Long,WeakReference>:put(threadId,弱引用)
hy20160705 commentedon Aug 8, 2019
单列模式
优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。
这种方式和上面的方式一样,只不过将类实例化的过程放入了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例,优缺点一样。
这种写法起到了Lazy Loading的效果,但是只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。
解决上面第三种实现方式的线程不安全问题,做个线程同步就可以了,于是就对getInstance()方法进行了线程同步。
缺点:效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低要改进。
由于第四种实现方式同步效率太低,所以摒弃同步方法,改为同步产生实例化的的代码块。但是这种同步并不能起到线程同步的作用。跟第3种实现方式遇到的情形一致,假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。
Double-Check概念对于多线程开发者来说不会陌生,如代码中所示,我们进行了两次if (singleton == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。
优点:线程安全;延迟加载;效率较高。
这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。
类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
优点:避免了线程不安全,延迟加载,效率高。
借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。可能是因为枚举在JDK1.5中才添加,所以在实际项目开发中,很少见人这么写过。
优点:系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
缺点:当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new,可能会给其他开发人员造成困扰,特别是看不到源码的时候。
适用场合:需要频繁的进行创建和销毁的对象;创建对象时耗时过多或耗费资源过多,但又经常用到的对象;工具类对象;频繁访问数据库或文件的对象
siren4 commentedon Aug 15, 2019
优点:
节省资源,线程安全.
缺点:
生命周期长,容易造成内存泄漏.
shenyuexin commentedon Aug 22, 2019
HashMap的函数是非同步的,不是线程安全的,这样没问题吗?
zywudev commentedon Dec 2, 2019
自己总结的:https://mp.weixin.qq.com/s/VUf-NP9W9Bb89OdgnyhY7w
huazidev commentedon Jun 1, 2020
什么是单例?
单例是一种设计模式,单例是整个系统中只能出现类的一个实例,即一个类只有一个对象。 单例模式的解决的痛点就是节约资源,减少内存开销。
设计单例主要考虑到确保一个实例,线程安全,提高效率,代码简洁几方面。
实现方式?
双重校验锁方式如果提到 volatile 可以问下 volatile 变量?
你推荐哪种方式?为什么?
个人推荐使用枚举,简单实用,线程安全,防止通过反射调用私有构造方法。
还能想到单例的其他问题吗?
不可以,因为构造方法私有化