美文网首页简述
简述Android Thread

简述Android Thread

作者: 萌码象C | 来源:发表于2017-12-14 17:21 被阅读0次

    目录:
    [TOC]

    线程

    • 什么是线程?

      • 线程是一种轻量级进程,大多数情况下用于执行异步操作。
      • 一个Android 程序开始运行的时候,会单独启动一个进程,同时会产生一个UI Thread线程。
      • 一个Android 程序默认情况下也只有一个Process,但一个Process下却可以有许多个Thread。
    • 线程与进程的区别

      1. 地址空间:
        • 线程是进程内的一个执行单元,一个进程至少有一个线程;
        • 线程共享进程的地址空间,而进程有自己独立的地址空间;
      2. 资源拥有:
        • 进程是资源分配和拥有的单位;
        • 同一个进程内的线程共享进程的资源;
      3. 线程是处理器调度的基本单位,但进程不是;
      4. 线程只需要很少的资源就可“轻装上阵”运行的优点,来弥补进程并发的“颗粒度”粗糙的缺点,提高系统资源利用率。
    • 为什么使用线程?

      • 在Android中线程分为主线程(UI线程)和子线程,主线程主要处理和界面相关的事情,而子线程则执行耗时操作。
      • 如果在主线程执行耗时操作时,如网络请求或数据库读取,就会阻塞主线程 其他逻辑的执行,导致程序无法及时响应从而导致界面卡顿。
      • 如果卡顿时间超过5秒,系统就会报ANR错误。所以,如果要执行耗时的操作,需要另起线程执行。
      • 注意:
        从Android 3.0 开始系统要求网络访问必须在子线程中进行,否则网络访问将失败并抛出NetworkOnMainThreadException异常,这样做是为了避免主线程由于耗时操作所阻塞从而出现ANR现象。
    • 线程的实现方法

      • 方法一:实现Thread

        • 扩展 java.lang.Thread 类

            Thread mThread=new Thread(new Runnable()    
                    {    
                        @Override    
                        public void run()    
                        {   
                            // method
                        }    
                });    
            mThread.start();
          
        • 实现 Runnable 接口

            public class ThreadTest extends Activity implements Runnable  
            {  
                @Override
                public void onCreate(Bundle savedInstanceState)
                {  
                    super.onCreate(savedInstanceState);  
                    setContentView(R.layout.main);  
            
                    Thread thread=new Thread(this);  
                    thread.start();  
                }  
          
                @Override  
                public void run()  
                {
                    // mothod 
                }  
            }
          
        • 继承 Thread 类与实现 Runnable 接口的区别

          • 在 Java API中,Thread是实现了Runnable接口;
          • 在 Java 中,类仅支持单继承,也就是说,当定义一个新的类的时候,它只能扩展一个外部类;
          • 使用实现Runnable接口的方式创建的线程可以处理同一资源,从而实现资源的共享。
      • 方法三:实现AsyncTask
        AsyncTask是一种轻量级的异步任务类,它可在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。
        AsyncTask封装了Thread和Handler,更加方便执行后台任务以及在主线程中访问UI,但不适合进行特别耗时的后台任务。
        AsyncTask是一个抽象的泛型类,提供了Params(参数类型)、Progess(后台任务的执行速度)和Result(后台任务的返回结果的类型)这三个泛型参数。

        • onPreExecute()
          开始执行前的准备工作;
        • doInBackground(Params...)
          开始执行后台处理,可以调用publishProgress方法来更新实时的任务进度;
        • onProgressUpdate(Progress...)
          在publishProgress方法被调用后,UI 线程将调用这个方法从而在界面上展示任务的进展情况;
        • onPostExecute(Result)
          执行完成后的操作,传送结果给UI线程。
        • onCancelled()
          在主线程中执行,任务被取消时调用,这个时候onPostExecute()则不会调用。
        • 注意:
          • AsyncTask的对象必须在UI线程中创建;
          • AsyncTask.execute()必须在UI线程中调用;
          • 除了doInBackground(Params...),其余方法都是被UI线程所调用的;
          • 一个AsyncTask对象只能被执行一次,即只能调用一次execute(),否则 将会出现运行时异常;
          • 这些方法都不能直接调用;
          • 不能手动停止。
          • Android版本区别
            • 在Android 1.6 之前,AsyncTask是串行执行任务的。
            • 在Android 1.6 的时候,AsyncTask采用线程池里处理并行任务。
            • 从Android 3.0 开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务。但,可以通过AsyncTask的executeOnExecutor()来并行地执行任务。
      • 方法四:实现IntentService
        IntentService继承了Service并且它是一个抽象类,IntentService封装了HandlerThread和Handler,用来处理异步请求,可执行后台耗时任务。
        IntentService通过worker thread处理每个Intent对象,执行完所有工作后自动停止Service。
        IntentService优先级比单纯的线程要高很多,所以适合执行高优先级的后台任务,因为不容易被系统杀死。

            public class IntentServiceTest extends IntentService {
                
                public IntentServiceTest() {   
                    super("IntentServiceTest");   
                }  
                
                @Override
                public IBinder onBind(Intent intent)
                {
                    return null;
                }
                
                @Override
                public void onCreate()
                {
                    super.onCreate();
                }
    
                @Override
                public int onStartCommand(Intent intent, int flags, int startId)
                {
                    return super.onStartCommand(intent, flags, startId);
                }
                
                @Override
                protected void onHandleIntent(Intent intent)
                {
                    try {
                        //耗时操作
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                
                @Override
                public void onDestroy()
                {
                    super.onDestroy();
                }
            }
            
            // 启动的IntentService
            Intent intent = new Intent(this, IntentServiceTest.class);   
            startService(intent); 
            startService(intent); 
            startService(intent); 
        
        
    * 方法五:实现HandlerThread
        HandlerThread继承Thread,是一种可以使用Handler的Thread,通过run方法中Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环。  
        由于HandlerThread的run方法是一个无限循环,在不使用时,需通过quit或者quitSafely方法来终止线程执行。
        
            public class HandlerThreadActivity extends Activity {  
                
                private static final int SIGN = 1;
            
                private HandlerThread mHandlerThread;
                private Handler mMsgHandler;
                private boolean isContinue;
    
                @Override
                protected void onCreate(Bundle savedInstanceState)
                {
                    super.onCreate(savedInstanceState);
                    setContentView(R.layout.activity_threadHandler);
            
                    //创建后台线程
                    initThread();
                }
    
                @Override
                protected void onResume()
                {
                    super.onResume();
                    //继续
                    isContinue = true;
                    mMsgHandler.sendEmptyMessage(SIGN);
                }
    
                @Override
                protected void onPause()
                {
                    super.onPause();
                    //停止继续
                    isContinue = false;
                    mMsgHandler.removeMessages(MSG_UPDATE_INFO);
                }
    
                private void initThread()
                {
                    mHandlerThread = new HandlerThread("handlerThread");
                    mHandlerThread.start();
                    mMsgHandler = new Handler(mCheckMsgThread.getLooper())
                    {
                        @Override
                        public void handleMessage(Message msg)
                        {
                            try {//模拟请求
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            
                            if (isContinue) {
                                mMsgHandler.sendEmptyMessageDelayed(SIGN, 1000);
                            }
                        }
                    };
                }
    
                @Override
                protected void onDestroy()
                {
                    super.onDestroy();
                    //释放资源
                    mHandlerThread.quit();
                }
            }
    

    琐机制

    Looper、Handler、MessageQueue、Message

    • Message
      消息体,封装了传输消息所需的数据结构。

    • Handler
      Message的主要处理者,负责Message的发送,Message内容的执行处理。

      • Handler会向message queue通过sendMessage或post两种方法发送消息

        • 都会插在message queue队尾并按先进先出执行
        • 通过sendMessage发送的是一个message对象,会被Handler的handleMessage()处理;
        • 通过post方法发送的是一个runnable对象,则会自己执行。
      • 使用Handler注意事项:

        • 创建massage对象时,推荐使用obtain()方法获取,因为Message内部会维护一个Message池用于Message的复用,这样就可以避免 重新new message而冲内心分配内存,减少new 对象产生的资源的消耗。
        • handler 的handleMessage方法内部如果有调用外部activity或者fragment的对象,一定要用弱饮用,handler最好定义成static的,这样可以避免内存泄漏;
          为什么呢?因为一但handler发送了消息。而handler内部有对外部变量的引用,此时handler已经进入了looper的messageQueue里面。此时activity或者fragment退出了可是区域,但是handler内部持有其引用且为强引用时,其就不会立即销毁,产生延迟销毁的情况;
        • 不确定当前线程时,更新UI时尽量调用post方法。
    • Lopper
      循环器,负责管理一个消息循环队列(MessageQueue)的。

    • MessageQueue
      消息队列,用来存放handler发布的消息,按照先进先出执行。

    • Thread、Lopper、Handler、MessageQueue 间关系

      • 一个 Thread 对应一个 Looper;

      • 一个 Looper 对应一个 MessageQueue;

      • 一个 Looper 可以对应多个 Handler;

      • 一个 Thread 可以有多个Handler;

      • 一个 Handler 只能和一个Thread 关联;

      • Handler 会引用当前线程里的特定 Looper 和 MessageQueue;

      • Handler 的处理过程运行在创建 Handler 的 Thread 里。

          class LooperThread extends Thread {   
        
              public Handler mHandler;   
             
              public void run() {   
                  Looper.prepare(); //创建本线程的Looper并创建一个MessageQueue  
             
                  mHandler = new Handler() {   
                      public void handleMessage(Message msg) {   
                          // process incoming messages here
                      }   
                  };   
               
                  Looper.loop(); //开始运行Looper,监听Message Queue   
              }   
          }
        

    操作多线程的方式

    1. Handler + Thread
    2. AsyncTask
    3. ThreadPoolExecutor
    4. IntentService

    子线程更新UI的方式

    1. View.post(Runnable action)
    2. Activity.runOnUiThread(Runnable action)
    3. AsyncTask
    4. Handler

    线程池

    • 什么是线程池?
      线程池能够对线程进行简单管理,因为线程不可能无限制的产生,并且线程的创建和销毁都会有相应的开销。
      线程池中会缓存一定数量的线程,通过这个线程池就可以避免频繁创建和销毁线程带来的系统开销。

      • 优点
        • 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销;
        • 能够有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
    • ThreadPoolExecutor
      ThreadPoolExecutor提供一系列参数来配置线程池,通过不同参数可以创建不同的线程池。

      • 构造函数

        • int corePoolSize
          线程池维护线程的最少数量。
          默认情况下,核心线程数会在线程池中一直存活,即使处于闲置状态。如果将ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为ture,那么闲置的核心线程在等待新任务到来时会有超时策略,这个时间间隔由keepLiveTime指定。当等待时间超过keepLiveTime,核心线程就会被终止。
        • int maximumPoolSize
          线程池维护线程的最大数量。
          活动线程达到这个数量,后续的新任务将会被阻塞。
        • long keepAliveTime
          线程池维护线程所允许的空闲时间,超过这个时长,线程就会被回收。
        • TimeUnit unit
          线程池维护线程所允许的空闲时间的单位,是一个枚举。
        • BlockingQueue<Runnable> workQueue
          线程池所使用的缓冲队列。
          通过线程池的execute方法提交的Runable对象会存储在这个参数中。
        • ThreadFactory threadFactory
          线程池用于创建线程。
          是一个接口,只有一个方法Thread newThread(Runnable r)。
        • RejectedExecutionHandler handler
          线程池对拒绝任务的处理策略。
          当线程池无法执行新任务时,可能是由于任务队列已满或者是无法成功执行任务,这个时候handler的rejectedExecution方法来通知调用者。
        • 配置参考(AsyncTask)
          • 核心线程数等于CPU核心数+1;
          • 最大线程数等于CPU核心数的2倍+1;
          • 核心线程无超时机制,非核心线程在闲置时的超时时间为1秒;
          • 任务队列的容量为128。
      • 线程创建规则
        ThreadPoolExecutor对象初始化时,不创建任何执行线程,当有新任务进来时,才会创建执行线程。

        • 当目前执行线程的总数小于核心线程大小时,所有新加入的任务,都在新线程中处理。
        • 当目前执行线程的总数大于或等于核心线程时,所有新加入的任务,都放入任务缓存队列中。
        • 当目前执行线程的总数大于或等于核心线程,并且缓存队列已满,同时此时线程总数小于线程池的最大大小,那么创建新线程,加入线程池中,协助处理新的任务。
        • 当所有线程都在执行,线程池大小已经达到上限,并且缓存队列已满时,就handler拒绝新的任务。
      • 线程池分类

        • FixedThreadPool
          通过Executors的newFixedThreadPool方法创建。
          线程数目固定且只有核心线程的线程池,线程处于空闲状态时,并不会被回收,除非线程池关闭。
          当所有线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。
          • 优点:只有核心线程并且不会被回收,能够更加快速的响应外界的请求。
        • CachedThreadPool
          通过Executors的newCachedThreadPool方法创建。
          线程数目不固定且只有非核心线程的线程池,并且最大线程数为Intager.MAX_VALUE。
          当所有线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则就会利用空闲的线程来处理新任务。空闲线程有超时机制,超时时长为60秒,超过就会被回收。
          • 优点:适合执行大量的耗时较少的任务,当线程池处于闲置状态,线程都会超时停止,不占用系统资源。
        • ScheduledThreadPool
          通过Executors的newScheduledThreadPool方法创建。
          核心线程数固定,非核心线程数不固定的线程池,并且当非核心线程闲置时立刻回收。
          • 优点:用于执行定时任务和具有固定周期的重复任务。
        • SingleThreadExecutor
          通过Executors的newSingleThreadExecutor方法创建。
          只有一个核心线程的线程池,确保所有任务都在同一个线程中按顺序执行。
          • 优点:统一将外界任务到一个线程中,不需要处理线程同步问题。
      • 线程池执行

        • execute()中,调用了三个私有方法
        • addIfUnderCorePoolSize()
          在线程池大小小于核心线程池大小的情况下,扩展线程池
        • addIfUnderMaximumPoolSize()
          在线程池大小小于线程池大小上限的情况下,扩展线程池
        • ensureQueuedTaskHandled()
          保证在线程池关闭的情况下,新加入队列的线程也能正确处理
      • 线程池关闭

        • shutdown()
          不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
        • shutdownNow()
          立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务

    相关文章

      网友评论

        本文标题:简述Android Thread

        本文链接:https://www.haomeiwen.com/subject/tdokwxtx.html