Android 性能优化<八> 多线程优化和线程管理

来源:互联网 发布:三国志群英会java 编辑:程序博客网 时间:2024/06/06 20:15
  • AsyncTask: 为 UI 线程与工作线程之间进行快速的切换提供一种简单便捷的机制。适用于当下立即需要启动,但是异步执行的生命周期短暂的使用场景。
  • HandlerThread: 为某些回调方法或者等待某些任务的执行设置一个专属的线程,并提供线程任务的调度机制。
  • ThreadPool: 把任务分解成不同的单元,分发到各个不同的线程上,进行同时并发处理。
  • IntentService: 适合于执行由 UI 触发的后台 Service 任务,并可以把后台任务执行的情况通过一定的机制反馈给 UI。
    了解这些系统提供的多线程工具类分别适合在什么场景下,可以帮助我们选择合适的解决方案,避免出现不可预期的麻烦。虽然使用多线程可以提高程序的并发量,但是我们需要特别注意因为引入多线程而可能伴随而来的内存问题。举个例子,在 Activity 内部定义的一个 AsyncTask,它属于一个内部类,该类本身和外面的 Activity 是有引用关系的,如果 Activity 要销毁的时候,AsyncTask 还仍然在运行,这会导致 Activity 没有办法完全释放,从而引发内存泄漏。所以说,多线程是提升程序性能的有效手段之一,但是使用多线程却需要十分谨慎小心,如果不了解背后的执行机制以及使用的注意事项,很可能引起严重的问题。




    . Android 系统的屏幕刷新频率为 60 fps, 也就是每隔 16 ms 刷新一次。如果在某次绘制过程中,我们的操作不能在 16 ms 内完成,那它则不能赶上这次的绘制公交车,只能等下一轮。

    这种现象叫做 “掉帧”,用户看到的就是界面绘制不连续、卡顿。



    ThreadPoolExecutor 

    使用线程池的好处可以归纳为3点:

    1. 重用线程池中的线程, 避免因为线程的创建和销毁所带来的性能开销.
    2. 有效控制线程池中的最大并发数,避免大量线程之间因为相互抢占系统资源而导致的阻塞现象.
    3. 能够对线程进行简单的管理,可提供定时执行和按照指定时间间隔循环执行等功能.

    不建议用ThreadPoolExecutor threadPoolExecutor= new ThreadPoolExecutor ();
    而是用Executors工厂类方法
    Executors类提供了4个工厂方法用于创建4种不同特性的线程池给开发者用.

    区别:线程池的长度(线程的个数),可回收,是否处于等待状态,是否支持周期性
    (1)newCachedThreadPool 创建一个可缓存线程池,线程池的最大长度无限制,但如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
       (2)   newFixedThreadPool  创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    (3)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
    (4)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Overridepublicvoidrun() { } },1,2, TimeUnit.SECONDS);



    常见几种BlockingQueue实现

         1. ArrayBlockingQueue :  有界的数组队列
      2. LinkedBlockingQueue : 可支持有界/无界的队列,使用链表实现
      3. PriorityBlockingQueue : 优先队列,可以针对任务排序
      4. SynchronousQueue : 队列长度为1的队列,和Array有点区别就是:client thread提交到block queue会是一个阻塞过程,直到有一个worker thread连接上来poll task。


    android中的线程池都是直接或是间接通过配置ThreadPoolExecutor来实现的.
    Executor和ExecutorService都是接口
    Executor mThreadPool = Executors.newFixedThreadPool(3);
    private ExecutorService  mThreadPool = Executors.newFixedThreadPool(3);
    public interface ExecutorService extends Executor {

    建线程池管理者 ThreadManager

    public class ThreadManager {    public static final int POOL_SIZE = 2;    public static ThreadManager mThreadManager = null;    private ExecutorService mExeService = null;    private int mCpuNum = 0;    public static synchronized ThreadManager instance() {        if (mThreadManager == null) {            mThreadManager = new ThreadManager();        }        return mThreadManager;    }    ThreadManager() {        mCpuNum = Runtime.getRuntime().availableProcessors();    }    public synchronized ExecutorService getExeService() {        if (mExeService == null || mExeService.isShutdown()) {            int threadNum = mCpuNum * POOL_SIZE;            if (threadNum > 3) {                threadNum = 3;            }            mExeService = Executors.newFixedThreadPool(threadNum);        }        return mExeService;    }
     
    实例:
    /** * 请求百度推荐的应用 */public void requestRecommendApp() {    CXLog.d(TAG, "requestRecommendApp");    if (!mIsRequesting.get() && mIsExistAppInto) {        mIsRequesting.set(true);        mInfoAdapter.updateAppIntoStatus();        ThreadManager.instance()                .getExeService()                .submit(new Runnable() {                    @Override                    public void run() {                        List<ApkModel> apkModelList = mInfoAdapter.getRequestApkList();                        if (apkModelList != null && apkModelList.size() > 0) {                            mApkNetworkUtil.requestIntoRecommendApp(apkModelList, getInstalledList());                            if(CXConfig.DEBUG){                                CXToastUtil.showToast(mContext,"请求服务器");                            }                        } else {                            runOnUiThread(new Runnable() {                                @Override                                public void run() {                                    if(CXConfig.DEBUG){                                        CXToastUtil.showToast(mContext,"直接导入");                                    }                                    mInfoAdapter.intoReceiveApkList(null);                                    intoFinish();                                    mIsExistAppInto = false;                                    mIsRequesting.set(false);                                }                            });                        }                    }                });    }}




    通过给线程加锁机制。来保证线程安全,以及当前程序当中只有一个x线程池ThreadPool

    public class ThreadUtil {    private static Executor threadPool = Executors.newCachedThreadPool();    public static void execute(Runnable runnable)    {        threadPool.execute(runnable);    }}

    升级版线程管理类:增加了同步机制

    /** * 线程管理者。 * * @author peng * */public class ThreadManager{    private static ThreadPool threadPool; // 单列的线程池对象。    /**     * 单列,线程安全     * 获取一个线程池对象     * @return     */    public static ThreadPool getThreadPool()    {        if (threadPool == null)        {            //枷锁            synchronized (ThreadManager.class)            {                if (threadPool == null)                {                    //核心线程数,等于处理器个数乘2                    int corePoolSize = Runtime.getRuntime().availableProcessors()*2;                    int maximumPoolSize = 10;                    long keepAliveTime = 0L;                    threadPool = new ThreadPool(corePoolSize, maximumPoolSize, keepAliveTime);                }            }        }        return threadPool;    }    public static class ThreadPool    {        public static ThreadPoolExecutor executor = null;        private int corePoolSize;        private int maximumPoolSize;        private long keepAliveTime = 0; // 限制线程的的最大存活时间        public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime)        {            super();            this.corePoolSize = corePoolSize;  //核心线程数            this.maximumPoolSize = maximumPoolSize; //最大线程 ,当核心线程用完时。决定是否开启最大线程            this.keepAliveTime = keepAliveTime;  //线程排队时间,        }        /**         * 线程池:就是把一堆线程放在一起来管理。 1.通过一定的管理机制。来处理线程额执行顺序 2.管理最多可以同时执行的线程数。         * 3.其他线程通过队列的形式,也就是排队的形式来管理线程的并发数。         *         * @param runnable         */        public void execute(Runnable runnable)        {            if (runnable == null)            {                return;            }            if (executor == null)            {                executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,                        TimeUnit.MILLISECONDS,// 时间单位                        new LinkedBlockingQueue<Runnable>(),// 线程队列                        Executors.defaultThreadFactory(),//线程工厂                        new AbortPolicy());            }            // 给线程池里面添加一个线程            executor.execute(runnable);        }    }}

     Profile GPU Rendering : M Update

    从 Android M 系统开始,系统更新了 GPU Profiling 的工具来帮助我们定位 UI 的渲染性能问题。早期的 CPU Profiling 工具只能粗略的显示出 Process,Execute,Update 三大步骤的时间耗费情况。