多线程操做

 

对于多线程的操做:有两种方式:网络

1.继承Thread类。new Thread(){run()}.start();多线程

2.实现Runnable类。new Thread(){new Runnable(){}}.start();异步

 

对于多线程的异步操做,处理方式有两种:oop

  1. Handler+Thread方式,即对Looper对象的管理
  2. AsyncTask
  3. 多线程的封装-线程池(线程池工厂或者自定义线程)

 

Handler+Thread方式:

对于Handler+Thread分为主线程与副线程的操做,只要咱们对Looper对象操做便可,将消息message或者runnable进行send或者post便可。布局

主线程:runOnUiThread(runnable action)、view.post(runnable action)、主线程的Handler.post(runnable action)、Handler.sendMessage(message)post

副线程:副线程的Handler.post(runnable action)性能

对于主线程的handler.sendMessage()再也不阐述,在activity上声明一个Handler,默认handler构造器就是与主线程的Looper绑定,即在Handler的handleMessage()都是在主线程上的操做。ui

对于不管主线程仍是副线程,针对handler.post(runnable action)的状况,Hanlder的封装以下:spa

/**
     * UI线程 handler
     **/
private static Handler mUiHandler;

/**
    *副线程handler
    **/
private static Handler SUB_THREAD1_HANDLER;

/**
     * 副线程1
     */
private static HandlerThread SUB_THREAD1;
/**
    * 锁
    **/
private static final Object mMainHandlerLock = new Object();

/**
     * 取得UI线程Handler
     *
     * @return
     */
    public static Handler getMainHandler() {
        if (mUiHandler == null) {
            synchronized (mMainHandlerLock) {
//                if (mUiHandler == null) {
                mUiHandler = new Handler(Looper.getMainLooper());
//                }
            }
        }
        return mUiHandler;
    }

/**
     * 得到副线程1的Handler.<br>
     * 副线程能够执行比较快但不能在ui线程执行的操做.<br>
     * 此线程禁止进行网络操做.若是须要进行网络操做.
     * 请使用NETWORK_EXECUTOR</b>
     *
     * @return handler
     */
    public static Handler getSubThread1Handler() {
        if (SUB_THREAD1_HANDLER == null) {
            synchronized (ThreadManager.class) {
                SUB_THREAD1 = new HandlerThread("SUB1");
                SUB_THREAD1.setPriority(Thread.MIN_PRIORITY);//下降线程优先级
                SUB_THREAD1.start();
                SUB_THREAD1_HANDLER = new Handler(SUB_THREAD1.getLooper());
            }
        }
        return SUB_THREAD1_HANDLER;
    }

 

 view.post()与handler.post()的区别,使用不当可能致使内存泄露:.net

相关:http://blog.csdn.net/a740169405/article/details/69668957

若是调用view.post()方法的线程对象被GC-root引用(慎用static修饰Thread),则会形成内存泄漏

由于:

  GC-root->Thread->ThreadLocal->ViewRootImpl->runnable

可是主线程除外,由于虽然主线程的runQueue没法被回收,可是每次执行完performTraversals(),都会将runQueue中的对象执行并清除。

常常咱们将线程池对象定为static进行复用,所以须要慎用view.post().

  

 

 runOnUiThread(runnable action)与view.post(runnable action)的对比

共同点:第一种runOnUiThread,和第二种view.post()都是要求主线程执行,都是经过获取主线程的handler,经过handler.post(),把action封装成message传到Looper的消息循环中,当handler再次处理该message时,直接调用action的run方法。

区别:view.post(runnable action)是在view初始化完成后才执行post(runnnable),而runOnUiThread()是主线程当即执行,若是在onCreate()进行初始化activity时,须要对布局文件中的控件进行调整时,直接使用runOnUiThread代替view.post可能会形成view的信息获取都为空。

由于在activity建立时,生命周期onCreate(),布局文件初始化还没完成,在onCreate()方法上,仅仅是将控件的相关信息写入内存,还没映射到设备上,所以控件信息还没初始化,广泛上初始化完成要在onResume()方法以后。

 

handler原理

咱们能够经过调用handler的post方法,把Runnable对象(通常是Runnable的子类)传过去;handler会在looper中调用这个Runnable的Run方法执行。

Runnable是一个接口,不是一个线程,通常线程会实现Runnable。因此若是咱们使用匿名内部类是运行在UI主线程的,若是咱们使用实现这个Runnable接口的线程类,则是运行在对应线程的。

View.post原理

View.post(Runnable)方法。在post(Runnable action)方法里,View得到当前线程(即UI线程)的Handler,而后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),而后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,所以,咱们能够毫无顾虑的来更新UI。

 拓展

若是咱们要进行耗时的操做,好比下载操做,咱们不能再UI线程;也不能直接在副线程直接进行下载,由于咱们要考虑多线程直接的顾虑,咱们引入线程池。

/**
     * AsyncTask的默认线程池Executor. 负责长时间的任务(网络访问) 默认3个线程
     */
    public static final Executor NETWORK_EXECUTOR;
    static {
        NETWORK_EXECUTOR = initNetworkExecutor();
    }
private static Executor initNetworkExecutor() {
        Executor result;
        // 3.0以上
        if (Build.VERSION.SDK_INT >= 11) {
            //result = AsyncTask.THREAD_POOL_EXECUTOR;
            result = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
                    new LinkedBlockingQueue<Runnable>());
        }
        // 3.0如下, 反射获取
        else {
            Executor tmp;
            try {
                Field field = AsyncTask.class.getDeclaredField("sExecutor");
                field.setAccessible(true);
                tmp = (Executor) field.get(null);
            } catch (Exception e) {
                tmp = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
                        new LinkedBlockingQueue<Runnable>());
            }
            result = tmp;
        }

        if (result instanceof ThreadPoolExecutor) {
            //线程数改成CPU 核数 +1
            ((ThreadPoolExecutor) result).setCorePoolSize(FitmixUtil.getPhoneCpuCoreNum() + 1);
        }

        return result;
    }
/**
     * 在网络线程上执行异步操做. 该线程池负责网络请求等操做 长时间的执行(如网络请求使用此方法执行) 固然也能够执行其余 线程和AsyncTask公用
     *
     * @param run
     */
    public static void executeOnNetWorkThread(Runnable run) {
        try {
            NETWORK_EXECUTOR.execute(run);
        } catch (RejectedExecutionException e) {
        }
    }

 

 

 AsyncTask

引言:

我不太赞成封装好就会影响性能的说法,在我实际的运用中,真正的缺点来自于AsyncTask的全局线程池只有5个工做线程,也就是说,一个APP若是运用AsyncTask技术来执行线程,那么同一时间最多只能有5个线程同时运行,其余线程将被阻塞(注:不运用AsyncTask执行的线程,也就是本身new出来的线程不受此限制),因此AsyncTask不要用于多线程取网络数据,由于极可能这样会产生阻塞,从而下降效率。

 

 

AsyncTask是封装好的线程池,比起Thread+Handler的方式,AsyncTask在操做UI线程上更方便,由于onPreExecute()、onPostExecute()及更新UI方法onProgressUpdate()均运行在主线程中,这样就不用Handler发消息处理了;

 

一个异步任务的执行通常包括如下几个步骤:

1.execute(Params... params),执行一个异步任务,须要咱们在代码中调用此方法,触发异步任务的执行。

2.onPreExecute(),在execute(Params... params)被调用后当即执行,通常用来在执行后台任务前对UI作一些标记。

3.doInBackground(Params... params),在onPreExecute()完成后当即执行,用于执行较为费时的操做,此方法将接收输入参数和返回计算结果。在执行过程当中能够调用publishProgress(Progress... values)来更新进度信息。

4.onProgressUpdate(Progress... values),在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。

5.onPostExecute(Result result),当后台操做结束时,此方法将会被调用,计算结果将作为参数传递到此方法中,直接将结果显示到UI组件上。

相关文章
相关标签/搜索