Android併發編程

Android的併發編程,即多線程開發,而Android的多線程開發模型也是源於Java中的多線程模型
因此本篇也會先講一些Java中的多線程理念,再講解具體涉及的類,最後深刻Android中的併發場景和實踐java

併發

什麼是併發

舉個很簡單的栗子,當你一邊在擼擼擼,一邊在看小視頻,同時在作兩件事,這就是併發。編程

咳,年輕人節制啊。安全

併發的好處

提升資源利用率

當一個任務並無徹底佔用系統資源,就能夠利用併發來提升資源利用率,同時也能更快地完成任務。多線程

當你的右手在幹些什麼的時候,左手是否是在沒事作呢?那就也用起來唄。
(某次聚會,一名騎馬的漢子說本身左右互搏(lu)特厲害)。併發

在程序任務上更加精簡

就拿上一個栗子來講,左手作什麼,右手作什麼,任務明確分配好,又能同時進行,既提升了效率,邏輯又清晰。app

更好的響應程序

這個拿Android客戶端舉個栗子,上傳圖片時,當前界面仍是正常運轉沒有卡死,圖片也正常上傳,既保證了界面被響應,又保證圖片能夠上傳。框架

併發的風險

併發的代價

  • 須要佔用更多的資源。
  • 設計好一個併發程序並不容易。
  • 併發的資源交互問題複雜。

併發的隱患

  • 濫用資源致使系統不穩定
  • 結果與預期不符
  • 出現BUG難以排查

線程篇

進程是什麼

就拿Android中的App來講,通常來講一個app就是一個進程,(除了特殊的手段開啓了多個進程,這裏不深刻這個話題,就是一個一對多的關係)。性能

線程是什麼

進程只是一個程序、任務的統稱,可是卻不能執行任務,真正執行任務的是線程,因此線程是由進程建立的,一個進程能夠建立多個線程。學習

線程能夠調度資源等等,在這裏只須要了解大體的概念就好,若是要深刻能夠學習一下操做系統操作系統

進程與線程的關係

人腦就至關因而CPU,想作一件事的時候,這個任務就是一個進程了,須要運用手腳等器官去完成這個任務,而手腳器官就能夠理解成一個個線程,去作了不一樣的事,從而完成任務。

單線程

仍是用Android舉栗子,當你在手機上操做的時候,這個被稱之爲UI線程(以後會詳解)。而一個最基本的app,不須要複雜的功能時,就只有一個UI線程和咱們交互,那麼這個app就是個單線程的。通常的程序面向用戶的線程就是UI線程,也稱之爲主線程,單線程程序,其實就是隻有一個主線程的程序。

多線程

多個進程能夠算是併發,可是咱們所說的併發場景,大部分是在一個進程中的,而併發就是由線程完成的,多個線程同時執行任務,就稱之爲併發。

如下爲多線程工做示意圖:

多線程

多線程併發過程當中會遇到的問題

1. 資源共享

A線程要寫文件C,B線程也要寫文件C,這個時候就好像你拿着兩隻筆同時往紙上寫東西,寫出來的是什麼本身也不知道。

這個時候咱們須要一個相似於的東西,當C被A在寫的時候,B不能寫,B要等A寫完了才能繼續寫。

至於這個究竟是什麼會在後面繼續講到。

3. 死鎖問題

死鎖的四個條件是:

  • 禁止搶佔:no preemption

  • 持有和等待:hold and wait

  • 互斥:mutual exclusion

  • 循環等待:circular waiting

預防死鎖就是至少破壞這四個條件其中一項,即破壞「禁止搶佔」、破壞「持有等待」、破壞「資源互斥」和破壞「循環等待」。

舉個例子:

A在B那邊割包皮,B把A割壞了,A佔着B的牀位,要B賠錢,B要A讓出牀位纔給錢。雙方僵持不下。

線程如何去用

在Java中,線程一般就是指Thread這個類,或者實現了Runnable的類,其實Thread這個類也是實現了Runnable接口的,能夠看一下Runnable接口的代碼:

Runnable

裏面就是一個run方法須要被實現。

再看一下Thread類的聲明:

Thread

確實是一個實現了Runnable的類。

那麼Thread類中擁有start()方法,和run()方法,下面用run()方法直接調用
獲得信息:

ThreadRun

發現其實和外面的線程是在同一個線程上。

而調用start()方法獲得的信息是:

ThreadStart

發現線程名不同了,用start會開啓一個新的線程,而run仍是在當前線程執行。

另外在Java1.5以後,還有Callable、Future和FutureTask,在這裏就不詳細介紹,還有線程的wait、
yield、sleep等在下一章會一塊兒詳細介紹。

線程的優先級

在Java中,線程的優先級有1~10,而默認的是5。1最低,10最高。在Thread類中有三個常量:

  • MIN_PRIORITY = 1

  • NORM_PRIORITY = 5

  • MAX_PRIORITY = 10

在同一個線程池中的線程優先級是相同的。

JVM會根據線程的優先級去搶先調度,然而線程的優先級只能保證搶佔資源的機率較大,並不能保障線程的執行順序,因此不能過於依賴設置線程的優先級。

線程池

頻繁地建立和銷燬線程會致使性能大幅度下降,這確定不是你但願的。

線程池的出現,就是爲了解決這個問題,根據java中提供不一樣的線程池機制,有效地提升資源利用率。

直接在代碼中建立Thread、Runnable去start或者run容易出現不可預測的問題,在java1.5開始,引入了java.util.concurrent包,其中有個併發的框架:Executor,使用ExecutorService替代直接操做線程類,而Executors是用來建立線程池的,內部提供了不少靜態方法去建立你想要的線程池,不須要你再手動去建立實現。
看一下關於Executor中的類和接口的大體的成員與關係:

concurrent

關於這些類如何使用,以及有什麼特性,下一章會做介紹。

隊列

在java中提到隊列確定會想起Queue,而線程隊列用的是BlockingQueue,這是個接口,在concurrent包中有好幾個類實現了這個接口。

BlockingQueue

介紹一下BlockingQueue經常使用的方法

  會異常 返回是否成功 會阻塞 設定等待時間
入隊列 add(e) offer(e) put(e) offer(e, timeout, unit)
出隊列 remove() poll() take() poll(time, unit)
查看值 element() peek() none none

線程安全

在前面講過死鎖,死鎖是因爲使用不當引發的一種現象,而這裏的鎖是人工干預的,讓併發按照你的意思走。

在java中的鎖有synchonrized、Lock。鎖的出現主要是爲了解決線程安全問題。

關於線程的狀態會在下一章講鎖的機制時候再講,由於線程的狀態會影響到鎖。

線程安全的集合

由於多線程訪問資源可能會形成數據不一致或者數據污染,而某些集合會用一些鎖或者同步機制作了處理。

線程安全的集合有:HashTable、SynchronizedCollection、ConcurrentHashMap、Vector等。

線程安不安全的首要前提是在多線程訪問同一個對象的狀況下。

相關文章
相關標籤/搜索