1. 程式人生 > >Android執行緒詳解

Android執行緒詳解

現在大多數的移動裝置已經變得越來越快,但是它們其實也不算是非常快。如果你想讓你的APP既可以承受一些繁雜的工作而又不影響使用者體驗的話,那麼必須把任務並行執行。在Android上,我們使用執行緒。

端一杯咖啡,然後仔細閱讀這篇文章。我會給大家介紹一下執行緒的概念,還有在Java中怎麼使用執行緒,線上程中怎麼使用Handler等。

如果需要使用非同步處理或者並行任務的話,那麼你一定會用到執行緒。

什麼是執行緒?

執行緒或者執行緒執行本質上就是一串命令(也是程式程式碼),然後我們把它傳送給作業系統執行。

一般來說,我們的CPU在任何時候一個核只能處理一個執行緒。多核處理器(目前大多數Android裝置已經都是多核)顧名思義,就是可以同時處理多執行緒(通俗地講就是可以同時處理多件事)。

多核處理與單核多工處理的實質

上面我說的是一般情況,並不是所有的描述都是一定正確的。因為單核也可以用多工模擬出多執行緒。

每個執行線上程中的任務都可以分解成多條指令,而且這些指令不用同時執行。所以,單核裝置可以首先切換到執行緒1去執行指令1A,然後切換到執行緒2去執行指令2A,接著返回到執行緒1再去執行1B、1C、1D,然後繼續切換到執行緒2,執行2B、2C等等,以此類推。

這個執行緒之間的切換十分迅速,以至於在單核的裝置中也會發生。幾乎所有的執行緒都在相同的時間內進行任務處理。其實,這都是因為速度太快造成的假象,就像電影《黑客帝國》裡的特工Brown一樣,可以變幻出很多的頭和手。

agent_brown_dodging_bullets

接下來我們來看一些程式碼。

Java核心裡的執行緒

在Java中,如果要想做平行任務處理的話,會在Runnable裡面執行你的程式碼。可以繼承Thread類,或者實現Runnable介面:

// Version 1 publicclass IAmAThread extendsThread { publicIAmAThread() { super("IAmAThread"); } @Override publicvoid run() { // your code (sequence of instructions)
} } // to execute this sequence of instructions in a separate thread. newIAmAThread().start(); // Version 2 publicclass IAmARunnable implementsRunnable { @Override publicvoid run() { // your code (sequence of instructions) } } // to execute this sequence of instructions in a separate thread. IAmARunnable myRunnable = newIAmARunnable(); newThread(myRunnable).start();

這兩個方法基本上是一樣的。第一個版本是建立一個Thread類,第二個版本是需要建立一個Runnable物件,然後也需要一個Thread類來呼叫它。

第二個版是通常建議使用的方法。這也是一個很大的主題了,超過了本文的範圍,以後會再做討論。

Android上的執行緒

無論何時啟動APP,所有的元件都會執行在一個單獨的執行緒中(預設的)——叫做主執行緒。這個執行緒主要用於處理UI的操作併為檢視元件和小部件分發事件等,因此主執行緒也被稱作UI執行緒。

如果你在UI執行緒中執行一個耗時操作,那麼UI就會被鎖住,直到這個耗時操作結束。對於使用者體驗來說,這是非常糟糕的!這也就是為什麼我們要理解Android上的執行緒機制了。理解這些機制就可以把一些複雜的工作移動到其它的執行緒中去執行。如果你在UI執行緒中執行一個耗時的任務,那麼很有可能會發生ANR(應用無響應),這樣使用者就會很快地結束掉你的APP。

Android和Java一樣,它支援使用Java裡面的Thread類來進行一步任務處理。所以可以輕鬆地像上面Java的例子一樣來使用Android上的執行緒,不過那好像還是有點困難。

為什麼在Android上使用標準Java的執行緒會困難呢?

其實平行任務處理沒有想象中的那麼簡單,你必須在多執行緒中保證併發,就像偉大的Tim Bray說的那樣:ordinary humans can’t do concurrency at scale (or really at all) …

特別對於Android來說,以下這些功能就略顯臃腫:

  1. 非同步對於UI執行緒來說是一個主要的PITA(如果你需要在後臺執行緒中向主執行緒更新介面,那麼你就會用到)。
  2. 如果螢幕方向或者螢幕配置改變的話,就會出現一些更加奇怪的現象。因為改變螢幕方向,會引起Activity重建(所以後臺執行緒就需要去改變被銷燬的Activity的狀態了,而如果後臺執行緒不是在UI執行緒之上的話,那情況會更加複雜,原因如條件1)。
  3. 對於執行緒池來說,沒有預設的處理方式。
  4. 取消執行緒操作需要自定義程式碼實現。

那麼在Android上怎麼進行任務併發處理呢?

你可能聽過一些Android上一些常見的名詞:

1、Handler
這就是我們今天要討論的詳細主題。

2、AsyncTask
使用AsyncTask是在Android上操作執行緒最簡單的方式,也是最容易出錯的方式。

3、IntentService
這種方式需要寫更多的程式碼,但是這是把耗時任務移動到後臺的很好的方式,也是我最喜歡的方式。配上使用一個EventBus機制的框架如Otto,這樣的話實現IntentService就非常簡單了。

4、Loader
關於處理非同步任務,還有很多事情需要做,比如從資料庫或者內容提供者那裡處理一些資料。

5、Service
如果你曾經使用過Service的話,你應該知道這裡會有一點誤區,其中一個常見的誤解就是服務是執行在後臺執行緒的。其實不是!看似執行在後臺是因為它們不與UI元件關聯,但是它們(預設)是執行在UI執行緒上的……所以預設執行在UI執行緒上,甚至在上面沒有UI部件。

如果想要把服務執行在後臺執行緒中,那麼必須自定義一個執行緒,然後把操作程式碼都執行在那個執行緒中(與上面提到的方法很類似)。事實上你應該使用IntentService實現,但是這不是本文討論的主題。

Android上的Handler

> A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread/message queue of the thread that is creating it — from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

為了更好地瞭解這個概念,也許你需要去看看什麼是Message Queues。

訊息佇列

線上程裡基本都有一個叫做“訊息佇列”的東西,它負責執行緒間通訊。這是一種設計模式,所有控制指令或者內容線上程間傳遞。

訊息佇列如同它的名字那樣,對於執行緒來說,它就是一個指令佇列。這裡我們還可以做一些更酷的事:

  • 定時訊息和執行緒在某個時間點才執行。
  • 需要在另一個執行緒中去新增入隊動作,而不是在本執行緒中。

注意:這裡說的“訊息”和Runnable物件、指令佇列的概念是一樣的。

回到Android上的Handler……如果你仔細閱讀的話,可以看到文件是這樣說的:

> A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue.

所以Handler可以讓你給執行緒佇列發訊息:

> Each Handler instance is associated with a single thread and that thread’s message queue.

一個Handler物件只能和一個執行緒關聯:

> When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it

所以一個Handler到底和哪個執行緒關聯呢?就是創造它的執行緒。

> — from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.、

在我們瞭解這些知識後,請繼續看……

小貼士: 這裡有幾點可能你還不知道。每個執行緒都和一個Handler類例項繫結,而且可以和別的執行緒一起執行,相互通訊。

還有一個小建議(如果用過AsyncTask的話),AsyncTask內部也是使用Handler進行處理的,只是不是執行在UI執行緒而已,它會提供一個channel來和UI執行緒通訊,使用postExecute方法即可實現。

這還挺酷的,那怎麼建立Handler呢?

有兩種方式:

  1. 使用預設的構造方法:new Handler()。
  2. 使用帶參的構造方法,引數是一個Runnable物件或者回調物件。

Handler裡面有什麼實用的API嗎?

請記住:

  • Handler只是簡單往訊息佇列中傳送訊息而已(或者使用post方式)
  • 它們有更方便的方法可以幫助與UI執行緒通訊。

如果你現在看看Handler的API,可以清楚看到這幾個方法:

  1. post
  2. postDelayed
  3. postAtTime

程式碼示例

這裡的程式碼都是很基礎的,不過你可以好好看看註釋。

示例1:使用Handler的“post”方法

相關推薦

Android--執行

什麼是執行緒? 執行緒或者執行緒執行本質上就是一串命令(也是程式程式碼),然後我們把它傳送給作業系統執行。 一般來說,我們的CPU在任何時候一個核只能處理一個執行緒。多核處理器(目前大多數Android裝置已經都是多核)顧名思義,就是可以同時處理多執行緒(通俗地

Android執行

現在大多數的移動裝置已經變得越來越快,但是它們其實也不算是非常快。如果你想讓你的APP既可以承受一些繁雜的工作而又不影響使用者體驗的話,那麼必須把任務並行執行。在Android上,我們使用執行緒。 端一杯咖啡,然後仔細閱讀這篇文章。我會給大家介紹一下執行緒的概念

Android程序與執行

        相信很多人讀過Google Android 推廣工程師的《Who lives and who dies? Process priorities on Android》,該篇僅僅詳細介紹了程序級別,但是沒有對android的程序進行詳細的介紹,而且其他很多文章

Android執行(幾種實現方法及區別)

一、Android執行緒的定義和特點     1.什麼是執行緒: 執行緒是一種輕量級程序,大多數情況下用於執行非同步操作。在一個Android 程式開始執行的時候,會單獨啟動一個程序,同時會產生一個UIThread執行緒(main執行緒)。一個Android 程式預設情況

Java執行

這篇文章計劃講一下整個Java執行緒的生命週期。 要了解一個執行緒,首先要從它的建立說起,然後是執行緒的執行以及執行緒與執行緒之間的互動,最後是執行緒的銷燬。 一、執行緒的建立 執行緒的建立有四種方式: 1)繼承Thread類建立執行緒 2)實現Runnable介面建立執行緒 3)使用C

執行(二)

多執行緒詳解(二) 在正式介紹執行緒建立的第二種方法之前,我們接著多執行緒詳解(一),講一下:對執行緒的記憶體圖、執行緒的狀態,為下面的學習打下基礎,小夥伴們不要急喲!! 一、多執行緒執行的記憶體圖(ps.博主沒有找到合適的畫圖工具,歡迎大神們貢獻啊) class pers

執行(一)

[多執行緒詳解(一)](http://www.neilx.com) 一、概念準備 1、程序 (1)直譯:正在進行中的程式 (2)解釋:執行一個程式時,會在記憶體中為程式開闢空間,這個空間就是一個程序。 (3)注意:一個程序中不可能沒有執行緒,只有有了執行緒才能執行; 程序只

面試題之——多執行

多執行緒作為Java中很重要的一個知識點,在此還是有必要總結一下的。 一.執行緒的生命週期及五種基本狀態 關於Java中執行緒的生命週期,首先看一下下面這張較為經典的圖: 上圖中基本上囊括了Java中多執行緒各重要知識點。掌握了上圖中的各知識點,Java中的多執行緒也就基本上掌握了。主

挑戰408——作業系統(6)——執行

20世紀80年代,人們提出了比程序更小,並能獨立執行的基本單位——執行緒。如果說程序的目的是為了讓多個程式彼此之間能夠併發執行,那麼引入執行緒就是為了減少併發執行所付出的時間和空間開銷。從而使得作業系統具有更好的併發性。 執行緒的作用 由於程序是一個資源的擁有者,因此在程序的建立

iOS開發多執行

在iOS開發中,多執行緒開發是非常重要的核心之一,這篇文章和大家分享一下多執行緒的進階-死鎖. iOS有三種多執行緒程式設計的技術,分別是:(一)NSThread(二)Cocoa NSOperation(三)GCD(全稱:Grand Central Dispatch) 如果你對多執行緒

Java執行(深度好文)

Java執行緒:概念與原理 一、程序與執行緒         程序是指一個記憶體中執行的應用程式,每個程序都有自己獨立的一塊記憶體空間,即程序空間或(虛空間)。程序不依賴於執行緒而獨立存在,一個程序中可以啟動多個執行緒。比如在Windows系統中,一個執行的ex

LINUX作業系統知識:程序與執行

當一個程式開始執行後,在開始執行到執行完畢退出這段時間內,它在記憶體中的部分就叫稱作一個程序。 Linux 是一個多工的作業系統,也就是說,在同一時間內,可以有多個程序同時執行。我們大家常用的單CPU計算機實際上在一個時間片段內只能執行一條指令。   那麼Linux是如何實現多程序的同時執行的呢?原來Linu

併發系列(五)-----執行

一 簡介 執行緒這個話題,不管是在面試中還是在工作中會經常的遇見。而併發程式設計的目的就是為了在儘量不影響程式的執行效率的情況下保證資料的安全性和正確性。要想理解執行緒首先要明白一些概念性的東西。 程序:具有一定獨立功能的程式關於某個資料集合上的一次執行活動,程序是系統進行資源分配和排程

Java多執行(面試回顧)

1,什麼是多執行緒 一個程序中可以併發多個執行緒,每條執行緒並行執行不同的任務,多執行緒能滿足程式設計師編寫高效率的程式來達到充分利用 CPU 的目的。 2,執行緒的生命週期   執行緒的五種基本狀態 新建狀態(New):執行緒物件建立後,就是這種狀態。

Java執行(1)-概念與原理

一、程序與執行緒         程序是指一個記憶體中執行的應用程式,每個程序都有自己獨立的一塊記憶體空間,即程序空間或(虛空間)。程序不依賴於執行緒而獨立存在,一個程序中可以啟動多個執行緒。比如在Windows系統中,一個執行的exe就是一個程序。         執行

Java執行(2)-建立與啟動

一、定義執行緒 1、擴充套件java.lang.Thread類。         此類中有個run()方法,應該注意其用法:public void run()         如果該執行緒是使用獨立的Runnable執行物件構造的,則呼叫該Runnable物件的run方

Java執行(3)-執行棧模型與執行的變數

要理解執行緒排程的原理,以及執行緒執行過程,必須理解執行緒棧模型。         執行緒棧是指某時刻時記憶體中執行緒排程的棧資訊,當前呼叫的方法總是位於棧頂。執行緒棧的內容是隨著程式的執行動態變化的,因此研究執行緒棧必須選擇一個執行的時刻(實際上指程式碼執行到什麼地方)。

Java執行(4)-執行狀態的轉換

一、執行緒狀態         執行緒的狀態轉換是執行緒控制的基礎。執行緒狀態總的可以分為五大狀態。用一個圖來描述如下:         1、新狀態:執行緒物件已經建立,還沒有在其上呼叫start()方法。         2、可執行狀態:當執行緒有資格執行,但排程程式

Java執行(6)-執行的互動

執行緒互動是比較複雜的問題,SCJP要求不很基礎:給定一個場景,編寫程式碼來恰當使用等待、通知和通知所有執行緒。 一、執行緒互動的基礎知識         SCJP所要求的執行緒互動知識點需要從java.lang.Object的類的三個方法來學習: void notif

Java執行(7)-執行的排程

Java執行緒:執行緒的排程-休眠         Java執行緒排程是Java多執行緒的核心,只有良好的排程,才能充分發揮系統的效能,提高程式的執行效率。         這裡要明確的一點,不管程式設計師怎麼編寫排程,只能最大限度的影響執行緒執行的次序,而不能做到精準控