關(guān)于單例在多線程中,鎖的作用是防止創(chuàng)建多個(gè)是實(shí)例。
由于理解不深刻,最近我走進(jìn)了一個(gè)怪圈,竟然想成了防止多線程,操作同一個(gè)實(shí)例。(算了 感覺最近有點(diǎn)懵逼)
其實(shí)如果同時(shí)操作同一個(gè)實(shí)例需要同步,在相應(yīng)的方法加鎖就可以解決。
主要可以分為兩大類
懶漢式:指全局的單例實(shí)例在第一次被使用時(shí)構(gòu)建。
餓漢式:指全局的單例實(shí)例在類裝載時(shí)構(gòu)建。
幾種實(shí)現(xiàn)方式
1、靜態(tài)內(nèi)部類
public class A1 {
private static class A1Holder {
private static final A1 INSTANCE = new A1();
}
public static final A1 getInstance() {
return A1Holder.INSTANCE;
}
private A1() {
}
}
由于內(nèi)部類延遲加載,只有在調(diào)用getInstance時(shí),才會初始化實(shí)例
從內(nèi)部類來看是餓漢式,從外部來看是懶漢式
2、創(chuàng)建靜態(tài)的實(shí)例,靜態(tài)實(shí)例會在裝載時(shí)構(gòu)建。再創(chuàng)建靜態(tài)方法獲取實(shí)例,這樣就能保證實(shí)例唯一。(餓漢式)
public class A2 {
private static final A2 ourInstance = new A2();
public static A2 getInstance() {
return ourInstance;
}
private A2() {
}
}
缺點(diǎn):
1、可能由于初始化的太早,造成資源的浪費(fèi)。
2、如果初始化本身依賴于一些其他數(shù)據(jù),那么也就很難保證其他數(shù)據(jù)會在它初始化之前準(zhǔn)備好。
適合: 使用單例占用資源少,不需要其他初始化數(shù)據(jù)。
3、枚舉
public enum A3 {
INSTANCE;
public void fun1(){
}
}
// call A3.INSTANCE.fun1();
(Android官網(wǎng)不建議使用enums,占用內(nèi)存多)
4、調(diào)用時(shí)創(chuàng)建,同步方法(懶漢式)
public class B1 {
private static B1 instance;
public static synchronized B1 getInstance(){//執(zhí)行效率低
if(instance ==null){
instance = new B1();
}
return instance;
}
private B1(){}
}
4.2、雙重檢查
public class B2 { //Double check
private static B2 instance;
public static B2 getInstance() {
if (instance == null) { // instance 可能為中間態(tài)
synchronized (B2.class) {
if (instance == null) {
instance = new B2(); //instance 可能創(chuàng)建內(nèi)存空間,但為形成實(shí)例
}
}
}
return instance;
}
private B2() {
}
}
4.3 雙重檢查 + volatile
public class B3 {
private volatile static B3 instance; //volatile 寫操作時(shí) 不能讀
public static B3 getInstance() {
if (instance == null) {
synchronized (B3.class) {
if (instance == null) {
instance = new B3(); //instance 可能創(chuàng)建內(nèi)存空間,但為形成實(shí)例
}
}
}
return instance;
}
private B3() {
}
}