單例設計模式是一種最常見的設計模式糙麦,其目的就是為了保證整個程序中只有一個實例歇攻,常見的場景都是一些特殊的類驮樊,比如管理類的實現(xiàn)粗恢。
實現(xiàn)單例模式方法:
1.構造函數(shù)私有柑晒,防止在外部 new 對象。
2.內(nèi)部提供一個靜態(tài)的方法眷射,讓外部調(diào)用來獲取這個單例匙赞。
餓漢式單例
/**
* Created by zhangl on 2019/1/2.
*
*
* 單例 - 餓漢式 隨著類的加載,就已經(jīng)new了對象
*
*/
public class Singleton1 {
private static Singleton1 mInstance = new Singleton1();
private Singleton1(){
}
public static Singleton1 getInstance(){
return mInstance;
}
}
懶漢式單例
/**
* Created by zhangl on 2019/1/2.
*
* 單例 - 懶漢式 只有在使用的時候才會去加載
*
*/
public class Singleton2 {
private static volatile Singleton2 mInstance;
private Singleton2(){
}
public static Singleton2 getInstance(){
if (mInstance == null){
synchronized (Singleton2.class){
if (mInstance == null){
mInstance = new Singleton2();
}
}
}
return mInstance;
}
}
代碼中可以看到使用了volatile關鍵字妖碉,加上volatile關鍵的目的:
1.防止從排序 - JMM通過happens-before法則保證順序執(zhí)行語義涌庭,如果想要讓執(zhí)行操作B的線程觀察到執(zhí)行操作A的線程的結果,那么A和B就必須滿足happens-before原則欧宜,否則坐榆,JVM可以對它們進行任意排序以提高程序性能。
2.線程可見性 - 多線程環(huán)境下冗茸,某個共享變量如果被其中一個線程給修改了猛拴,其他線程能夠立即知道這個共享變量已經(jīng)被修改了,當其他線程要讀取這個變量的時候蚀狰,最終會去內(nèi)存中讀取愉昆,而不是從自己的工作空間中讀取。
關于volatile關鍵字麻蹋,可以寫一個測試類:
/**
* Created by zhangl on 2019/1/2.
*/
public class VolatileTest {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
if(td.isFlag()){
System.out.println("------------------");
break;
}
}
// 執(zhí)行結果跛溉? flag= true ------------------
}
}
class ThreadDemo implements Runnable {
private volatile boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
測試結果如下:
volatile測試.png
利用單例模式實現(xiàn)Activity管理類:
/**
* Created by zhangl on 2019/1/2.
*
*
* Activity 管理類
*
*
*/
public class ActivityManager {
private static volatile ActivityManager mInstance;
private Stack<Activity> mActivitys;
private ActivityManager(){
mActivitys = new Stack<>();
}
public void attach(Activity activity){
mActivitys.add(activity);
}
public void detach(Activity detachActivity){
// 一邊循環(huán)一邊移除 會出問題
/*for (Activity activity : mActivities) {
if(activity == detachActivity){
mActivities.remove(activity);
}
}*/
int size = mActivitys.size();
for (int i = 0;i < size;i++){
Activity activity = mActivitys.get(i);
if (activity == detachActivity){
mActivitys.remove(i);
i--;
size--;
}
}
}
/**
* 獲取當前Activity
* @return
*/
public Activity getCurrentActivity(){
return mActivitys.lastElement();
}
}