MS
Handler
用于線程間通信,要素有handler, message, message queue, looper
子線程創建handler之前必須創建looper,looper prepare() 會 創建message queue
new handler時候會綁定到當前Thread中Threadlocal的looper
looper.loop的時候會開始輪訓Meesage隊列
發送消息調用messagequeue.enqueue()調用native方法喚醒讓message.next()執行
取消息for(;;){message.next()}沒有消息的話會調用Native方法 讓出CPU,如果是主線程的話,
Activity沒有事情做休眠也是可以的
一個線程可以創建多個handler,每個handler會放入message的target變量里面
一個looper可以對應多個handler.
匿名內部類會默認持有外部類的引用,所以要是用靜態內部類,如果需要引用Actvity context,可以使用weakReference<>
軟引用在內存不足的時候GC會被清理
弱引用GC就會清理
UI空間不支持多線程操作,而且加鎖容易造成死鎖,使UI邏輯復雜。
子線程textview.setText("")
https://baijiahao.baidu.com/s?id=1620358105307361783&wfr=spider&for=pc
Looper是保證Activity工作的循環操作,如果Looper退出的話ActivityThread就結束了,Activity的生命周期就是依靠looper來控制的,所以looper死循環不存在的,message.next()會調用native方法判斷nativemessagequeue,為空的話讓出CPU
會把消息根據時間順序 插入messagequeue隊列
不能,需要創建Looper使用looper.prepare(),或者直接使用handlerThread.
Message最好使用obtain方法,Obtain會從meesage pool中獲取message,減少創建message的開銷,這里使用的是享元模式式即:Flyweight,它是對象池的一種實現。享元模式用來盡可能的減少內存的使用量。多用于存在大量重復對象的場景,或需要緩沖池的時候。用來緩存共享的對象。這樣來避免內存移除等。
每個Thread只有一個Looper實例,保存在ThreadLocal里面
自己不能new Looper實例,因為Looper構造方法是private的
在子線程中new handler時候傳入主線程looper對象即可與主線程通信
AsyncTask就是對Handler的封裝,有四個方法onprepare(主) doinbackground(子線程) onpostprogress(主) oncomplete(主)
線程
控制并發,管理線程(定時,單線程),快速執行減少創建和銷毀的開銷
newCachedThreadPool() 最大線程數Integer.MAX_VALUE 任務量大耗時少場景
newFixedThreadPool(int nThreads) 適用于任務量固定 且運行時間較長的場景 核心線程=最大線程不銷毀 超過核心線程的任務阻塞在無界的LinkedBlockingQueue
ScheduledThreadPoolExecutor(int corePoolSize) 適用于執行定時任務和具體固定周期的重復任務 DelayedWorkQueue
newSingleThreadExecutor() 按順序執行 LinkedBlockingQueue
參數有 核心線程數(一直存在不會銷毀) 最大線程數 等待時間(超時銷毀) 等待時間單位 線程隊列 線程工廠 拒絕策略(拋異常或者拋棄新任務 丟掉老任務)
handler asynctask intentService Rxjava handlerThread
SerialExecutor(保證順序執行)+ThreadPool(線程池 執行) +sHandler(主線程looper)
Service+handlerThread onhandleintent執行耗時任務 任務執行完自己關閉service
主線程創建thread一般是執行短暫的異步任務
service創建的thread一般是執行長期的任務 如長連接
1核心線程沒滿放入核心線程2隊列沒滿放入隊列3線程池沒滿創建線程池執行
Handler用于線程間通信,Thread用于開啟并運行新線程,HandlerThread自己會創建Handler的Thread
threadlocal tl = new ThreadLocal();
Thread1{ tl.set(123)}
Thread2{tl.set(234)}
set的時候調用的是Thread內部的threadLocals.
不一定,主要用于異步操作把耗時任務放到后臺,提高用戶體驗,多用于IO 網絡 操作
缺點是線程太多造成CPU競爭,CPU需要不停切換線程,處理同步問題
懶漢雙重檢查加同步鎖(懶加載)
餓漢(創建線程前已經建好)
還有notifayall(),notify只喚醒一個等待的線程,notifyall喚醒所有等待的線程,然后多個線程通過競爭得到鎖
在生產消費者模式下,如果只喚醒一個進程的話可能
Activity5秒 broadcast 10秒 service 20秒 不要在主線程做耗時操作
查看data/anr trace
情景
1 binder調用導致anr,如果不需要返回值的話就在AIDL方法參數定義in(c-s)不需要等待返回
2 主線程等待鎖,使用trylock解決
3 主線程做耗時操作
4 系統IO文件操作導致ANR,將文件操作放入子線程 ANRManager: 100% TOTAL: 2% user + 2.1% kernel + 95% iowait + 0.1% softirq
5 JE NE后系統dump信息導致ANR,解決JE NE即可
6 每個進程只分配15個binder線程,短時間大量binder調用可能導致超出的binder請求得不到處理
7 mokey可不處理
如果當前線程==獲得鎖的線程 則可以獲取鎖 鎖count++, 釋放一個鎖的話count--,如果count ==0的話才釋放
公平和非公平鎖的隊列都基于鎖內部維護的一個雙向鏈表,表結點Node的值就是每一個請求當前鎖的線程。
公平鎖則在于每次都是依次從隊首取值。
非公平鎖:在等待鎖的過程中, 如果有任意新的線程妄圖獲取鎖,都是有很大的幾率直接獲取到鎖的。
線程池的七個參數為核心線程數,最大線程數,等待時間,等待時間單位,線程隊列,線程工廠,拒絕策略
步驟1執行任務,如果核心線程滿 進入隊列,如果隊列滿,新建線程,如果超過最大線程的話 執行拒絕策略
常見線程池
固定線程池:核心線程等于最大線程,隊列使用無邊界的likedBlockQueue,適用于知道線程數,并且時間較長的任務
緩存線程池:大量耗時較少的任務
scheduledThreadPool:
singletonThreadPool:按順序執行 不需要同步操作 要求順序執行的任務如數據庫操作 文件操作 應用安裝
進程是應用的實體,一個應用至少有一個進程
線程是CPU調度的最小單元,App的主線程就是ActivityThread, 他里面的ApplicationThread是用來和AMS通信的binder.Activity啟動后會有主線程和幾個binder線程(用于AMS WMS通信)。
Handler asynctask rxjava handlerthread intentService
可以 子線程創建handler需要綁定Looper,綁定子線程looper需要使用looper.prepare() 然后用looper.loop()
也可以直接使用HandlerThread
線程池可以控制并發,減少新建/銷毀線程的開銷,可以控制線程執行間隔和執行順序
7個參數 核心線程數 最大線程數 超時時間 超時時間單位 線程隊列 線程工廠 拒絕策略
核心線程->隊列->線程->拒絕策略
Thread+runnable, Thread(FutureTask(Callable)), asyncTask,handlerThread,rxjava
webView 大圖 定位 push 不穩定操作(保護主線程)
可以使用更多內存,每個進程分配的內存固定,兩個進程就可以拿到兩倍內存
數據結構與算法
鏈表(遍歷使用迭代器效率高) 數組 棧(先進后出) 隊列(隊尾入隊 隊首刪除這點和棧不同) hashmap
sort(start, end)
{
int pivor = findPivot(start, end)
sort(start, pivot-1)
sort(pivot+1,end)
}
findPivot(){
while(){
while right--
while left++
}
}
swap(int a,int b)
1.7頭插進鏈表,1.8尾插進鏈表,長度超過8數組不大于64先擴容
Bitmap
h*w*ARGB_8888(4)
LruCache DiskLRUcache
LinkedHashMap按訪問排序,最新最近訪問的放在鏈表尾端。
性能優化
會發生GC 回收內存
不考慮縮放的話 500*500*4/1024 = 976Kb
webview首次初始化耗時長,優化打開頁面速度,創建全局webview,應用啟動就創建webview實例
H5頁面拉取優化,把html,css,js,image等資源預置在客戶端本地預置在應用內部提高加載速度
webview加載圖片最慢 可以先加載內容(setBlockNetworkImage(boolean)方法)然后再加載圖片:在onPageStarted時屏蔽圖片加載,在onPageFinished時開啟圖片加載。
設計模式
懶漢 惡漢
加鎖是讓多線程訪問同步
兩次判空,第一次判空是防止取鎖 競爭是是防止排隊中的線程創建多個實例
Java
Broadcast
Activity
Service
?
Android原理
進程間通信
網絡
實際問題
基礎
https://www.jianshu.com/p/ca2ecc3ea0f0
https://www.jianshu.com/p/81a17da4d695
作者:秀葉寒冬
鏈接:https://www.jianshu.com/p/c8dd2cb55b81
來源:簡書
總結
- 上一篇: 平均值,方差计算(sss)
- 下一篇: 编程的精髓:发现问题,解决问题