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