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