文章目录
单例设计模式:
是一种最最常见的一种模式,保证整个程序中只有一个实例,常用的场景一般都是一些特殊的类,比如:老板,管理类等等(皮肤的管理,Activity的管理)。
套路:
- 构造函数私有,防止在外部 new 对象
- 内部必须提供一个静态的方法,让外部调用
饿汉式
/**
* 单例 - 饿汉式
*/
public class Singleton {
//随着类的加载就已经new了对象
private static Singleton mInstance = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return mInstance;
}
}
懒汉式
/**
* 单例 - 懒汉式
*/
public class Singleton2 {
//只有使用的时候才去new对象(第一次调用getInstance时初始化),可能更加高效
// private static Singleton2 mInstance = new Singleton2();
private static Singleton2 mInstance;
private Singleton2(){
}
public static Singleton2 getInstance(){
if(mInstance == null){
mInstance = new Singleton2();
}
return mInstance;
}
}
public class Singleton3 {
//但是 懒汉式单例模式 会有多线程并发问题,如果多线程调用还是会存在多个实例
private static Singleton3 mInstance;
private Singleton3() {
}
//虽说解决了线程安全的问题,但是又会出现效率的问题,
//每次都要经过同步锁的判断,这种模式一般不建议使用
public static synchronized Singleton3 getInstance() {
if (mInstance == null) {
mInstance = new Singleton3();
}
return mInstance;
}
}
/**
* Double Check Lock(DCL)
*
* DCL方式实现单例模式的优点是既能够在需要时才初始化单例,又能够保证线程安全,
* 且单例对象初始化后调用getInstance不进行同步锁
*/
public class Singleton4 {
private static Singleton4 mInstance;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (mInstance == null) {
synchronized (Singleton4.class) {
if (mInstance == null) {
mInstance = new Singleton4();
}
}
}
return mInstance;
}
}
问题:
Singleton4 mInstance = new Singleton4()
- 开辟一块内存空间
- 初始化对象
- 给变量赋值,将mInstance对象指向分配的内存空间(此时mInstance就不是null了)
执行顺序可能是1-2-3 ,也可能是1-3-2。 如果是后者,3执行完毕(mInstance不为null),2未执行(未初始化对象),此时切换到另一个线程B,因为mInstance不为null,线程B直接取走mInstance,再使用时就会出错。
加上volatile 关键字
- 防止重排序
- 线程可见性 - 某一个线程改了公用对象(变量),短时间内另一个线程可能是不可见的,因为每一个线程都有自己的缓存区(线程工作区)
public class Singleton5 {
private static volatile Singleton5 mInstance;
private Singleton5() {
}
public static Singleton5 getInstance() {
if (mInstance == null) {
synchronized (Singleton5.class) {
if (mInstance == null) {
mInstance = new Singleton5();
}
}
}
return mInstance;
}
}
volatile 小例子
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;
}
}
// 执行结果? 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,只会输出 “flag=true”
静态内部类
静态内部类单例模式
/**
* 单例设计模式-静态内部类
*
* 只有在第一次调用getInstance方法才导致mInstance被初始化,
* 因此第一次调用getInstance方法会导致虚拟机加载SingletonHolder类,
* 这种方式不仅能够确保线程安全,也能够保证单例对象的唯一性,同时也延迟
* 了单例的实例化,这是推荐使用的单例模式实现方式
*/
public class Singleton5 {
private Singleton5() {
}
public static Singleton5 getInstance() {
return SingletonHolder.mInstance;
}
public static class SingletonHolder {
private static final Singleton5 mInstance = new Singleton5();
}
}
容器管理
/**
* 单例设计模式 - 容器管理
* 系统的服务就是使用这种
*/
public class Singleton6 {
private static Map<String, Object> map = new HashMap<>();
private Singleton6() {
}
public static void registerService(String key, Object instance) {
if (!map.containsKey(key)) {
map.put(key, instance);
}
}
public static Object getService(String key) {
return map.get(key);
}
}
Activity管理类
实现方式有如下:
1 EventBus
2 广播
3 集合管理
4 SingleTask
单点登录,弹框需要上下文,统一写到BaseActivity中?
import android.app.Activity;
import java.util.Stack;
public class ActivityManager {
private static volatile ActivityManager mInstance;
// 集合用谁 List LinkedList Stack ?? 删除和添加比较多
private Stack<Activity> mActivities;
private ActivityManager() {
mActivities = new Stack<>();
}
// 虽说解决了线程安全的问题,但是又会出现效率的问题,
// 即保证线程的安全同是效率也是比较高的
// 这种方式其实还是会有问题?
public static ActivityManager getInstance() {
if (mInstance == null) {
synchronized (ActivityManager.class) {
if (mInstance == null) {
mInstance = new ActivityManager();
}
}
}
return mInstance;
}
/**
* 添加统一管理
*/
public void attach(Activity activity) {
mActivities.add(activity);
}
/**
* 移除解绑 - 防止内存泄漏
*/
public void detach(Activity detachActivity) {
// for 去移除有没有问题? 一边循环一边移除会出问题 ,
// 既然这个写法有问题,自己又想不到什么解决方法,参考一下别人怎么写的
/*for (Activity activity : mActivities) {
if(activity == detachActivity){
mActivities.remove(activity);
}
}*/
int size = mActivities.size();
for (int i = 0; i < size; i++) {
Activity activity = mActivities.get(i);
if (activity == detachActivity) {
mActivities.remove(i);
i--;
size--;
}
}
}
/**
* 关闭当前的 Activity
*/
public void finish(Activity finishActivity) {
// for 去移除有没有问题?
/*for (Activity activity : mActivities) {
if(activity == finishActivity){
mActivities.remove(activity);
activity.finish();
}
}
*/
int size = mActivities.size();
for (int i = 0; i < size; i++) {
Activity activity = mActivities.get(i);
if (activity == finishActivity) {
mActivities.remove(i);
activity.finish();
i--;
size--;
}
}
}
/**
* 根据Activity的类名关闭 Activity
*/
public void finish(Class<? extends Activity> activityClass) {
// for 去移除有没有问题?
/*for (Activity activity : mActivities) {
if(activity.getClass().getCanonicalName().equals(activityClass.getCanonicalName())){
mActivities.remove(activity);
activity.finish();
}
}*/
int size = mActivities.size();
for (int i = 0; i < size; i++) {
Activity activity = mActivities.get(i);
if (activity.getClass().getCanonicalName().equals(activityClass.getCanonicalName())) {
mActivities.remove(i);
activity.finish();
i--;
size--;
}
}
}
/**
* 退出整个应用
*/
public void exitApplication() {
}
/**
* 获取当前的Activity(最前面)
*/
public Activity currentActivity() {
return mActivities.lastElement();
}
}