單例
單例模式是一種對象的創(chuàng)建模式,用于產(chǎn)生一個對象的具體實例碍舍,他可以確保系統(tǒng)中既忆,只有一個實例,減少new的次數(shù)驱负,因而對系統(tǒng)內(nèi)存的使用頻率也會降低,減輕GC的壓力患雇,縮短GC停頓的時間
惡漢式單例
public class HungrySingle {
private final static HungrySingle SINGLE = new HungrySingle();
private HungrySingle() {
System.out.println("HungrySingle is init");
}
public static HungrySingle instance() {
return SINGLE;
}
}
- 此種方式跃脊,是在虛擬機(jī)加載該類的時候,就加載該類的實例苛吱,無法對實例進(jìn)行延時的加載
懶漢模式
public class LazySingle {
public static LazySingle SINGLE = null;
private LazySingle() {
}
public static LazySingle instance() {
if (null == SINGLE) {
SINGLE = new LazySingle();
}
return SINGLE;
}
}
- 優(yōu)點:保證了延時的加載
- 缺點:不能保證線程的安全匾乓,容易重復(fù)創(chuàng)建多個實例,在多線程的情況下又谋,這種模式是失效的拼缝,無法保證單個實例
懶漢線程安全
public class LazySingle {
public static LazySingle SINGLE = null;
private LazySingle() {
}
//一種方式
public static synchronized LazySingle instance01(){
if (null==SINGLE){
SINGLE = new LazySingle();
}
return SINGLE;
}
//二種方式
public static LazySingle instance02() {
synchronized (LazySingle.class) {
if (null == SINGLE) {
SINGLE = new LazySingle();
}
return SINGLE;
}
}
}
該方式保證了線程安全,但有點影響性能彰亥,
懶漢Dcl模式
public class LazySingle {
public static LazySingle SINGLE = null;
private LazySingle() {
}
public static LazySingle instance03() {
//避免了不必要的同步
if (null == SINGLE) {
synchronized (LazySingle.class) {
//初次的時候初始化對象
if (null == SINGLE) {
SINGLE = new LazySingle();
}
}
}
return SINGLE;
}
}
- 優(yōu)點: 解決了性能問題咧七,和線程安全的問題
- 缺點:1、在理想狀態(tài)下任斋,jvm先給對象分配內(nèi)存继阻,調(diào)用構(gòu)造方法初始化對象,將對象指向分配的內(nèi)存空間。jvm在及時編譯器中有指令重排序的優(yōu)化瘟檩,不會完全按照這個步驟去創(chuàng)建對象抹缕,這個就造成了線程不安全的問題。
懶漢DCL優(yōu)化
- 解決辦法就是添加關(guān)鍵字 volatile 保證線程在本地不會存在instance的副本墨辛,每次都會到內(nèi)存中去讀取. 使用該關(guān)鍵字卓研,就是禁用了jvm指令重排序優(yōu)化,避免造成線程安全的問題
public class LazySingle {
//添加 volatile關(guān)鍵字
public static volatile LazySingle SINGLE = null;
private LazySingle() {
}
public static LazySingle instance03() {
//避免了不必要的同步
if (null == SINGLE) {
synchronized (LazySingle.class) {
//初次的時候初始化對象
if (null == SINGLE) {
SINGLE = new LazySingle();
}
}
}
return SINGLE;
}
}
單例-靜態(tài)內(nèi)部類
- 推薦使用這種方式
- 靜態(tài)內(nèi)部類: jvm提供給我們的同步控制睹簇,static 可以進(jìn)行區(qū)塊初始化的操作奏赘,保證數(shù)據(jù)在內(nèi)存是獨一份的,final初始化之后太惠,是無法被修改的磨淌,所也是線程安全的。(jvm在加載內(nèi)的時候保證類的同步)
- 是要我們不使用內(nèi)部類凿渊,就不會再次創(chuàng)建實例對象
- 這種方式是在性能梁只,和線程安全上更有優(yōu)化的
public class InnerStaticSingle {
private InnerStaticSingle() {
}
public static InnerStaticSingle instance() {
return SingleHolder.SINGLE;
}
//靜態(tài)內(nèi)部類
private static class SingleHolder {
private static final InnerStaticSingle SINGLE = new InnerStaticSingle();
}
}
單例-枚舉
- 寫法簡單,線程安全
- 不寫實例方法的話埃脏,默認(rèn)的情況下敛纲,枚舉的創(chuàng)建是線程安全的,如果自己添加實例剂癌,需要注意線程安全.
- 注意:在使用成員變量和成員方法的時候淤翔,需要保證線程安全
public enum EnumSingle {
//定義一個枚舉的常量就是一個實例
INSTANCE;
//在使用成員變量和成員方法的時候,需要保證線程安全
public void say() {
}
}
Android 單例實際運用
- Application
- 單例引起內(nèi)存年泄漏
- eventbus的坑