Android线程池详解

来源:互联网 发布:上海每日房屋成交数据 编辑:程序博客网 时间:2024/06/07 15:15

android中经常会用到多线程,因为安卓中如果5S中没有响应就会出现ANR,因此耗时的任务必须放在子线程中使用。这就涉及到UI线程(main线程)和子线程的交互。其二者之间的交互涉及到Handler,Looper,message。
每次创建线程都有系统资源的开销,不可能无限的创建线程,线程过多最终会带来系统的反应速度下降,因此就必须控制线程数量,控制线程的最好办法就是设计线程池,让线程可以重复利用。
下面将会通过三种方式来创建安卓的线程池。
1、通过静态列表缓存10个子线程,创建一个主线程,每个线程中创建唯一Handler,放在子线程的代码。
2、自定义线程池中还是设计一个主线程(UI线程),同时缓存10个子线程,当然这里创建的子线程采用android提供的HandlerThread来代替上面自定义的线程。采用HandlerThread会更加简便,后续会通过代码进行说明。
3、通过系统提供的ThreadPoolExecutor来设计线程池。

一、自定义Thread来创建线程池。

public class ThreadExtractors {    public class WorkThead extends Thread {        private boolean mIsQuiting = false;        private boolean mIsLoopEnd = false;        Handler myHandler = null;        private final String mThreadId;        public WorkThead(String threadId){            mThreadId = threadId;        }        @Override        public void run() {            //Looper.prepare() 和 Looper.loop()成对存在,创建Handler必须指定looper否则会抛异常            //需要通过synchronized来保证线程安全            Looper.prepare();            synchronized (this){                myHandler = new Handler();                //myHandler创建成功通知所有等待的线程                notifyAll();            }            Looper.loop();        }        public Handler getHandler(){            synchronized (this) {                while (null == myHandler) {                    try {                        //如果myHandler没创建成功,就需要等待,直到myHandler被创建成功                        wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }            return myHandler;        }        public void  quit(){            //退出时需要清除句柄,避免内存泄露            if (mIsQuiting)                return;            mIsQuiting = true;            if (null != myHandler){                //清除message队列及其回调                myHandler.removeCallbacksAndMessages(null);                myHandler.post(new Runnable() {                    @Override                    public void run() {                        Looper.myLooper().quit();                        mIsLoopEnd = true;                    }                });            }        }        public boolean isQuiting(){            return mIsQuiting;        }        public boolean isLoopEnd(){            return this.mIsLoopEnd;        }    }    //最大线程数量    private static final int MAX_TREAD_COUNT = 10;    private static final int minThreadCount = 5;    //当前线程数    private static int currentThreadCount = 0;    //保留的线程数    private static int RETENTION_THREAD_COUNT = 10;    private WorkThead[] retentionThreads;    private static ThreadExtractors THREAD_POOL = null;    private static Handler mainHandler = null;    private ThreadExtractors(){        mainHandler = new Handler(Looper.getMainLooper());        //子线程数目为10个        retentionThreads = new WorkThead[RETENTION_THREAD_COUNT];        for(int i = 0; i < RETENTION_THREAD_COUNT; i ++){            retentionThreads[i] = newThread();        }    }    private WorkThead newThread(){        String threadId = UUID.randomUUID().toString();        WorkThead workThead = new WorkThead(threadId);        workThead.start();        return workThead;    }    public void OnDestroy(){        if (null == retentionThreads)            return;        for (int i = 0, length = retentionThreads.length; i < length; i++){            retentionThreads[i].quit();        }        mainHandler.removeCallbacksAndMessages(null);        retentionThreads = null;        THREAD_POOL = null;    }    public static void extractMainThread(Runnable runnable){        THREAD_POOL.extractMainThread(runnable, 0);    }    public synchronized static void extractMainThread(Runnable runnable, int delayTime){        if (null == THREAD_POOL)            THREAD_POOL = new ThreadExtractors();        THREAD_POOL.mainHandler.postDelayed(runnable, delayTime);    }    public static void extractInThread(Runnable runnable){        THREAD_POOL.extractThread(runnable, 0);    }    public synchronized static void extractThread(Runnable runnable, int delayTime){        if (null == THREAD_POOL)            THREAD_POOL = new ThreadExtractors();        currentThreadCount++;        if(currentThreadCount >= MAX_TREAD_COUNT)            currentThreadCount = 0;        THREAD_POOL.retentionThreads[currentThreadCount].getHandler().postDelayed(runnable, delayTime);    }    private HandlerThread newHandlerThread(){        HandlerThread handlerThread = new CusmHandlerThread(UUID.randomUUID().toString());        handlerThread.start();        return handlerThread;    }    /** HandlerThread内部中已经封装好了线程安全,因此不必担心多线程问题     *     */    public class CusmHandlerThread extends  HandlerThread{        private Handler mMyHandler = null;        public CusmHandlerThread(String name) {            super(name);            mMyHandler = new Handler(this.getLooper());        }        public void setHandler(Handler handler){            mMyHandler = handler;        }        public Handler getHandler(){            return this.mMyHandler;        }    }}

对以上线程池代码进行讲解:
1、从66行 -75行可以看出,本线程池定义了1个主线程,10个子线程。
2、110行 extractMainThread(Runnable runnable, int delayTime)方法中加上同步关键字synchronized,是为了避免多线程安全问题。
3、需要注意子线程类WorkThead的定义,本线程只会创建Handler,创建Handler的时候请注意,每个Handler必须制定唯一的looper,因此如果需要自己创建非主线程的Handler,则必须将其创建放在Looper.prepare() 和 Looper.loop()之间,直到创建完成为止。
4、注意23行的getHandler()加了synchronized,是因为避免获取的时候其还没创建成功。
5、注意37行的quit()函数,退出的时候需要清理资源,避免内存泄露。

有没发现自定义线程WorkThead的实现相对来说比较繁琐,有没有更简便的方法呢?当然是有的,这就需要用到安卓封装的HandlerThread。
1、请查看129行~152行的HandlerThread定义,其功能完全可以代替WorkThead的功能,并且不用理会线程安全及其清理工作, HandlerThread内部会自动的去处理。当然HandlerThread内部也实现了线程安全问题。

下面看看以上设计的线程怎样调用:

        ThreadExtractors.extractMainThread(() ->{            System.out.println("这里的代码是在UI线程执行的,本消息会在主线程的Handler的消息队列中排队处理");        });        ThreadExtractors.extractInThread(() -> {            System.out.println("这里的代码是在非主线程中执行的,本消息会在非主线程的Handler的消息队列中排队处理");        });

本代码中采用了JAVA8中的新特性拉姆表达式,不熟悉的谷歌一下。
需要在主线程或者子线程执行,直接套用以上方法即可,当然每个线程post的messge会在当前线程的handler中进行排队,并且是顺序执行的。

原创粉丝点击