zoukankan      html  css  js  c++  java
  • Android ListView避免多线程加载一个同一资源

    当我们的ListView中的Item包含图片,而且这些图片是同一资源,我们用多线程去加载图片,这时候可能就发生了这种情况。

    比如线程是人,第一个人去做加载图片到缓存的工作,还没做好时第二个人要这同一张张图,结果缓存还没有这张图,于是第二个人也去加载图片到缓存。。以此类推,同时可能有N个人在加载同一张图,N取决于图片没加载到缓存前,可见的Item数量。

    于是针对这种情况进行细化同步,避免发生。

    //首先需要一个ConcurrentHashMap<String, Boolean>,String表示资源地址如图片地址,Boolean表示是否有线程正在加载。
    //之所以用ConcurrentHashMap,是因为它不但是同步的而且效率高于Synchronized和ReenTrantLock.
    private ConcurrentHashMap<String, Boolean> mConcurentMap;
    //然后需要一个ReentrantLock锁住线程内的关键判断语句。
    private ReentrantLock mLock;

     当一个线程没有在缓存找到资源,那么将读取资源,ConcurrentHashMap记录这个资源地址,并且Boolean为true,表示有人在干这个活了,下面的人只要等待干活的人干完就行了。

    //这是加载图片的线程,当缓存中没找到图片(mBitmapCache.get(path) == null)进入此线程
    Thread thread = new Thread() {
           @Override
           public void run() {
               mLock.lock();//锁住关键判断逻辑,避免同一资源多个线程都进入false逻辑(加载图片)
               if (mConcurentMap.get(path) == false) {
                   // mConcurentMap添加键值对,表示path这个资源已经有人在加载了
                   mConcurentMap.put(path, true);
                   mLock.unlock(); //释放锁,下面进入的线程只能进入true的逻辑(等待第一个人做完工作)
                   if (path != null && (!path.equals("null"))                                                        && (!"".equals(path))) {
                       //加载图片
                       item.bm = PictureHelper.getCropImage(path, 400, true, 100,mActivity, 7, true);
                       //图片加载完放入缓存Lrucache
                       mBitmapCache.put(path, item.bm);
                       //设置键值对,false表示path这个资源已经加载完,或者没人加载了
                       mConcurentMap.put(path, false);
                    } else {
                       item.bm = null;
                       //图片地址无效
                       mConcurentMap.put(path, false);
                    }
                    Message msg = new Message();
                    msg.what = 1;
                    handler.sendMessage(msg); 
                } else {
                    // 释放锁
                    mLock.unlock();
                    // 表示有人在加载图片,因此用死循环等待加载完成
                    while (true) {
                        // false表示加载完成,此时缓存已有图片,应该跳出循环
                        if (mConcurentMap.get(path) == false) {
                            // Logg.D("other need break cycle");
                            break;
                        }
                    }
                    // Logg.D("other go out cycle");
                    if (mBitmapCache.get(path) != null) {
                        item.bm = mBitmapCache.get(path);
                        Message msg = new Message();
                        msg.what = 2;
                        handler.sendMessage(msg);
                    } else {
                        throw new NullPointerException("(mBitmapCache.get(path) == null!");
                    }
                }
            }
        };
        executors.execute(thread);
  • 相关阅读:
    极简Docker和Kubernetes发展史
    什么是健身
    《高效休息法》IT从业者如何高效休息
    《我们赖以生存的隐喻》文学中的面向对象
    sequelize时间自动格式化
    什么是消息队列
    node.js中this指向失效解决
    node.js的async和await
    node.js箭头函数使用
    node.js如何批量赋值
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/4270128.html
Copyright © 2011-2022 走看看