双重加锁检查机制的应用
双重加锁检查和单例
1.近日,在做项目中实现集合的异步回调功能,使用了双重加锁检查的机制解决同步问题,原先代码如下:
public void obtainNewestInterface(Context context, UpdateBean config, ObtainListener obtainListener) { if (mUpdateObject == null) { mObtainListeners.add(obtainListener); if (mObtainListeners.size() <= 1) { this.execute(null, context, config); } } else { obtainListener.onSucceed(mUpdateObject); } }这个函数用于获取一个功能的最新对象,如果此对象已经加载完毕(行3),直接回调(行15)。
否则,将回调加入集合中(行5),如果队列没有在运行加载任务(行9),就可以加载启动任务,加载任务的部分代码如下:
@Override public void onPostExecute(Object result, String taskid) { if (result != null) { mUpdateObject = (IAd) result; for (ObtainListener listener : mObtainListeners) { listener.onSucceed(mUpdateObject); mObtainListeners.clear(); } } }加载最新功能对象完成后,将遍历需要加载的集合(行9),一一回调(行11),然后清空(行13)。
这个是没有逻辑问题,但是在多线性同时调用obtainNewestInterface方法的时候,会产生同步的问题,由于没有加入同步锁,会导致集合的对象出现以下错误:
1.线程A运行至加载完成,遍历回调的时候,线程B运行至mObtainListeners.add(obtainListener);,会出现同步错误。
2.线程A运行至加载完成,遍历完成的时候,线程B运行至判断是否需要提交任务,这时候size=2,线程A遍历完成,线程B不再提交任务,那么B任务就不会回调
于是加入了锁安全,代码如下:
public void obtainNewestInterface(Context context, UpdateBean config, ObtainListener obtainListener) { if (mUpdateObject == null) { synchronized (mObtainListeners) { mObtainListeners.add(obtainListener); if (mObtainListeners.size() <= 1) { this.execute(null, context, config); } } } else { obtainListener.onSucceed(mUpdateObject); }} @Override public void onPostExecute(Object result, String taskid) { if (result != null) { mUpdateObject = (IAd) result; synchronized (mObtainListeners) { for (ObtainListener listener : mObtainListeners) { listener.onSucceed(mUpdateObject); } mObtainListeners.clear(); } } }这样就解决了如上问题,可是仔细品味一番,新的问题又来了:
1. 线程A执行在遍历,线程B被锁至 if (mUpdateObject == null) {
2.线程B执行遍历完毕,清空集合,此时object不为空,锁解除,线程B进入锁代码,会继续add,此时size=1,会继续提交任务
本质是为了判断object为空就加载一次,回调全部,所以就又加上在锁里面判空,代码如下:
public void obtainNewestInterface(Context context, UpdateBean config, ObtainListener obtainListener) { if (mUpdateObject == null) { synchronized (mObtainListeners) {//代码加入判空 if (mUpdateObject != null) { obtainListener.onSucceed(mUpdateObject); } else { mObtainListeners.add(obtainListener); if (mObtainListeners.size() <= 1) { this.execute(null, context, config); } } } } else { obtainListener.onSucceed(mUpdateObject); } }//以下代码不变 @Override public void onPostExecute(Object result, String taskid) { if (result != null) { mUpdateObject = (IAd) result; synchronized (mObtainListeners) { for (ObtainListener listener : mObtainListeners) { listener.onSucceed(mUpdateObject); } mObtainListeners.clear(); } } }搞定! 博主可以写的再详细些