一、單例模式的特點(diǎn)
1、單例類只能有一個(gè)實(shí)例
2又固、單例類必須創(chuàng)建自己的唯一實(shí)例
3、單例類必須給所有其他對(duì)象提供這一實(shí)例
5煤率、單例模式保證了全局對(duì)象的唯一性
二仰冠、線程安全問(wèn)題
在獲取單例對(duì)象時(shí),要保證不能產(chǎn)生多個(gè)實(shí)例對(duì)象涕侈,由于使用單例對(duì)象時(shí)沪停,單例對(duì)象內(nèi)的實(shí)例變量是會(huì)被多線程共享的煤辨,所以為了避免這種問(wèn)題的出現(xiàn)我們需要使用無(wú)狀態(tài)對(duì)象裳涛,其不會(huì)因?yàn)槎鄠€(gè)線程的調(diào)度而破壞自身的狀態(tài)導(dǎo)致線程安全問(wèn)題
三、單例模式的實(shí)現(xiàn)
1众辨、餓漢式(靜態(tài)常量) 可用
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
優(yōu)點(diǎn):寫(xiě)法簡(jiǎn)單端三,在類裝載時(shí)就完成了初始化,避免了線程同步問(wèn)題
缺點(diǎn):在類裝載的時(shí)候就完成初始化鹃彻,沒(méi)有達(dá)到Lazy loading的效果 郊闯,如果沒(méi)有用過(guò)這個(gè)實(shí)例,則會(huì)造成內(nèi)存的浪費(fèi)
2蛛株、餓漢式(靜態(tài)代碼塊) 可用
public class Singleton1{
private static Singleton1 instance;
static {
instance = new Singleton1();
}
private Singleton1(){}
public static Singleton1 getInstance(){
return instance;
}
}
其優(yōu)缺點(diǎn)與上面那種方式是一樣的 只是寫(xiě)法不同
如果使用kotlin書(shū)寫(xiě)?zhàn)I漢式單例如下:
object SingletonKT {
}
只需使用 object 進(jìn)行對(duì)象聲明即可
3团赁、懶漢式(線程不安全) 不可用
Java實(shí)現(xiàn)
public class Singleton2{
private static Singleton2 instance;
private Singleton2(){}
public static Singleton2 getInstance(){
if (instance == null){
instance = new Singleton2();
}
return instance;
}
}
Kotlin實(shí)現(xiàn)
class SingletonDemo private constructor(){
companion object{
private var instance:SingletonDemo ?= null
get(){
if (field == null){
field = SingletonDemo()
}
return field
}
fun get():SingletonDemo{
//這里不用getInstance作為為方法名,是因?yàn)樵诎樯鷮?duì)象聲明時(shí)
// 谨履,內(nèi)部已有g(shù)etInstance方法欢摄,所以只能取其他名字
return instance!!
}
}
}
優(yōu)點(diǎn):這種寫(xiě)法起到了Lazy Loading的效果
缺點(diǎn):只能在單線程中使用,在多線程下有一定幾率會(huì)出現(xiàn)多個(gè)實(shí)例
4笋粟、懶漢式(線程安全怀挠,同步方法) 不推薦用
Java實(shí)現(xiàn)
public class Singleton3{
private static Singleton3 instance;
private Singleton3(){}
public static synchronized Singleton3 getInstance(){
if (instance == null){
instance = new Singleton3();
}
return instance;
}
}
Kotlin實(shí)現(xiàn)
class SingletonDemo private constructor(){
companion object{
private var instance:SingletonDemo ?= null
get(){
if (field == null){
field = SingletonDemo()
}
return field
}
@Synchronized
fun get():SingletonDemo{
//這里不用getInstance作為為方法名析蝴,是因?yàn)樵诎樯鷮?duì)象聲明時(shí)
// ,內(nèi)部已有g(shù)etInstance方法绿淋,所以只能取其他名字
return instance!!
}
}
}
優(yōu)點(diǎn):線程同步
缺點(diǎn):加鎖效率太低
5闷畸、懶漢式(線程安全,同步代碼塊) 不可用
Java實(shí)現(xiàn)
public class Singleton4{
private static Singleton4 instance;
private Singleton4(){}
public static Singleton4 getInstance(){
if (instance == null){
synchronized(Singleton4.class){
instance = new Singleton4();
}
}
return instance;
}
}
優(yōu)點(diǎn):效率較同步方法來(lái)說(shuō)吞滞,效率提高了
缺點(diǎn):并沒(méi)有起到同步效果佑菩,會(huì)出現(xiàn)多個(gè)實(shí)例
6、雙重檢查 推薦使用
Java實(shí)現(xiàn)
public class Singleton5{
private static volatile Singleton5 instance;
private Singleton5(){}
public static Singleton5 getInstance(){
if (instance == null){
synchronized (Singleton5.class){
if (instance == null){
instance = new Singleton5();
}
}
}
return instance;
}
}
Kotlin實(shí)現(xiàn)
class SingletonDemo1 private constructor(){
companion object{
val instance:SingletonDemo1 by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED){
SingletonDemo1()
}
}
}
優(yōu)點(diǎn):線程安全裁赠,延遲加載倘待,效率較高
7、靜態(tài)內(nèi)部類 推薦使用
Java實(shí)現(xiàn)
public class Singleton6{
private Singleton6(){}
private static class SingletonInstance{
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance(){
return SingletonInstance.INSTANCE;
}
}
Kotlin實(shí)現(xiàn)
class Singleton6{
private Singleton6(){}
private static class SingletonInstance{
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance(){
return SingletonInstance.INSTANCE;
}
}
優(yōu)點(diǎn):避免了線程不安全组贺,延遲加載凸舵,效率高
8、枚舉 推薦使用
Java實(shí)現(xiàn)
enum Singleton7{
INSTANCE;
}
優(yōu)點(diǎn):避免多線程同步失尖,還能反序列化重新創(chuàng)建新的對(duì)象
四啊奄、單例對(duì)象使用場(chǎng)景
? 需要頻繁的進(jìn)行創(chuàng)建和銷毀的對(duì)象
? 創(chuàng)建對(duì)象時(shí)耗時(shí)過(guò)多或耗費(fèi)資源過(guò)多,但又經(jīng)常用到的對(duì)象
? 工具類對(duì)象
? 頻繁訪問(wèn)數(shù)據(jù)庫(kù)或文件的對(duì)象
五掀潮、單例與靜態(tài)方法的區(qū)別
單例模式:可以實(shí)例化菇夸,方法可以重寫(xiě),因此靈活性較大
靜態(tài)方法:不需要實(shí)例化仪吧,因此不會(huì)在堆空間占用空間
選擇:如果不需要依賴于其他類或資源時(shí)庄新,用靜態(tài)方法,這時(shí)就是一個(gè)面向過(guò)程的函數(shù)而已薯鼠,如果需要依賴其他類的實(shí)例择诈,或者需要某些資源時(shí),用單例