Java-gt;Android并发编程引气入门篇
Android的并發編程,即多線程開發,而Android的多線程開發模型也是源于Java中的多線程模型。
所以本篇也會先講一些Java中的多線程理念,再講解具體涉及的類,最后深入Android中的并發場景和實踐。
并發
什么是并發
舉個很簡單的栗子,當你一邊在擼擼擼,一邊在看小視頻,同時在做兩件事,這就是并發。
咳,年輕人節制啊。
并發的好處
提高資源利用率
當一個任務并沒有完全占用系統資源,就可以利用并發來提高資源利用率,同時也能更快地完成任務。
當你的右手在干些什么的時候,左手是不是在沒事做呢?那就也用起來唄。
(某次聚會,一名騎馬的漢子說自己左右互搏(lu)特厲害)。
在程序任務上更加精簡
就拿上一個栗子來說,左手做什么,右手做什么,任務明確分配好,又能同時進行,既提高了效率,邏輯又清晰。
更好的響應程序
這個拿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接口的代碼:
里面就是一個run方法需要被實現。
再看一下Thread類的聲明:
確實是一個實現了Runnable的類。
那么Thread類中擁有start()方法,和run()方法,下面用run()方法直接調用
得到信息:
發現其實和外面的線程是在同一個線程上。
而調用start()方法得到的信息是:
發現線程名不一樣了,用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中的類和接口的大致的成員與關系:
關于這些類如何使用,以及有什么特性,下一章會作介紹。
隊列
在java中提到隊列肯定會想起Queue,而線程隊列用的是BlockingQueue,這是個接口,在concurrent包中有好幾個類實現了這個接口。
介紹一下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等。
線程安不安全的首要前提是在多線程訪問同一個對象的情況下。
預告
本節中挖的坑,一些沒有展開講的東西,會在下一節中填上。
感謝
《Java并發編程實踐》
《Thinking in Java》
baoyongzhang(鮑老師)
http://abner-nimengbo.cn/2016/08/13/AndroidMultipeThreadProgram/總結
以上是生活随笔為你收集整理的Java-gt;Android并发编程引气入门篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Application Provided
- 下一篇: Java-gt;Android并发编程筑