这里借鉴了一个篇写非常不错的博客:https://www.cnblogs.com/android-blogs/p/5530239.html
什么是设计模式?
设计模式(Design pattern)是一套被反复使用的代码设计经验的总结。使用设计模式的目的是为了可重用代码、让代码更容易被他人理解。设计模式是是软件工程的基石脉络,如大厦的结构一样。
单例模式
在这之前先要了解单例模式,什么是单例模式?
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
单例模式的优点:
- 对于那些比较耗内存的类,只实例化一次可以大大提高性能,尤其是在移动开发中。
- 保持程序运行的时候该中始终只有一个实例存在内存中
单例有很多种实现方式,这里列出其中1种。
public class Single {
private static volatile Single instance = null; //单例使用volatile修饰
private Single(){ //构造函数必须私有化,防止外部可以调用构造函数进行实例化
}
public static Single getInstance() { //必须定义一个静态函数获得该单例
if (instance == null) {
synchronized (Single.class) { //使用synchronized 进行同步处理,并且双重判断是否为null
if (instance == null) {
instance = new Single();
}
}
}
return instance;
}
}
要保证单例,需要做一下几步
- 必须防止外部可以调用构造函数进行实例化,因此构造函数必须私有化。
- 必须定义一个静态函数获得该单例
- 单例使用volatile修饰
- 使用synchronized 进行同步处理,并且双重判断是否为null,我们看到synchronized (Single.class)里面又进行了是否为null的判断,这是因为一个线程进入了该代码,如果另一个线程在等待,这时候前一个线程创建了一个实例出来完毕后,另一个线程获得锁进入该同步代码,实例已经存在,没必要再次创建,因此这个判断是否是null还是必须的。
单例的并发测试,可以使用CountDownLatch,使用await()等待锁释放,使用countDown()释放锁从而达到并发的效果。如下:
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(1); //CountDownLatch传入1,待完成线程减1
int threadCount = 1000;
for (int i = 0; i < threadCount; i++) {
new Thread() {
@Override
public void run() {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Single.getInstance().hashCode());
}
}.start();
}
latch.countDown();
}
看看打印出来的hashCode会不会出现不一样即可,理论上是全部都一样的。
不了解CountDownLatch可以先看:https://blog.csdn.net/Nobody_else_/article/details/97623701
而在Android中,很多地方用到了单例。
比如Android-Universal-Image-Loader中的单例
private volatile static ImageLoader instance; //单例使用volatile修饰
/** Returns singleton class instance */
public static ImageLoader getInstance() { //必须定义一个静态函数获得该单例
if (instance == null) {
synchronized (ImageLoader.class) { //使用synchronized 进行同步处理,并且双重判断是否为null
if (instance == null) {
instance = new ImageLoader();
}
}
}
return instance;
}
EventBus中的单例
private static volatile EventBus defaultInstance; //单例使用volatile修饰
public static EventBus getDefault() { //必须定义一个静态函数获得该单例
if (defaultInstance == null) {
synchronized (EventBus.class) { //使用synchronized 进行同步处理,并且双重判断是否为null
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
上面的单例都是比较规规矩矩的,当然实际上有很多单例都是变了一个样子,单本质还是单例。
如InputMethodManager 中的单例
static InputMethodManager sInstance;
public static InputMethodManager getInstance() {
synchronized (InputMethodManager.class) {
if (sInstance == null) {
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
sInstance = new InputMethodManager(service, Looper.getMainLooper());
}
return sInstance;
}
}
AccessibilityManager 中的单例,看代码这么长,其实就是进行了一些判断,还是一个单例
private static AccessibilityManager sInstance;
public static AccessibilityManager getInstance(Context context) {
synchronized (sInstanceSync) {
if (sInstance == null) {
final int userId;
if (Binder.getCallingUid() == Process.SYSTEM_UID
|| context.checkCallingOrSelfPermission(
Manifest.permission.INTERACT_ACROSS_USERS)
== PackageManager.PERMISSION_GRANTED
|| context.checkCallingOrSelfPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL)
== PackageManager.PERMISSION_GRANTED) {
userId = UserHandle.USER_CURRENT;
} else {
userId = UserHandle.myUserId();
}
IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
sInstance = new AccessibilityManager(context, service, userId);
}
}
return sInstance;
}
当然单例还有很多种写法,比如饿汉式,最后,我们应用一下单例模式。典型的一个应用就是管理我们的Activity,下面这个可以作为一个工具类。
public class ActivityManager {
private static volatile ActivityManager instance;
private Stack<Activity> mActivityStack = new Stack<Activity>();
private ActivityManager(){
}
public static ActivityManager getInstance(){
if (instance == null) {
synchronized (ActivityManager.class) {
if (instance == null) {
instance = new ActivityManager();
}
}
return instance;
}
public void addActicity(Activity act){
mActivityStack.push(act);
}
public void removeActivity(Activity act){
mActivityStack.remove(act);
}
public void killMyProcess(){
int nCount = mActivityStack.size();
for (int i = nCount - 1; i >= 0; i--) {
Activity activity = mActivityStack.get(i);
activity.finish();
}
mActivityStack.clear();
android.os.Process.killProcess(android.os.Process.myPid());
}
}
饿汉模式和懒汉模式
懒汉模式
在类加载的时候不被初始化。
public class Single {
//在对象加载的时候只进行一次
private static Single single = new Single();
private Single() {}
public static Single getSingle(){
return single;
}
}
饿汉模式
在类加载时就完成了初始化,但是加载比较慢,获取对象比较快。
public class LazySingle {
private static LazySingle lazySingle = null;
private LazySingle(){
}
//需要的时候才初始化
public synchronized static LazySingle getInstance(){ //线程不安全,加锁
if (lazySingle == null) {
lazySingle = new LazySingle();
}
return lazySingle;
}
饿汉模式是线程安全的,在类创建好一个静态对象提供给系统使用,懒汉模式在创建对象时不加上synchronized,会导致对象的访问不是线程安全的。
未完待续...