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

  • 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() { @Overridepublic void run() { } },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 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(),// 线程队列
                            Executors.defaultThreadFactory(),//线程工厂
                            new AbortPolicy());
                }
                // 给线程池里面添加一个线程
                executor.execute(runnable);
            }
    
        }
    }

     Profile GPU Rendering : M Update

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

你可能感兴趣的:(性能优化)