### 線程
#### 1、線程池的好處? 四種線程池的使用場景,線程池的幾個參數的理解?
> * 參考回答:
> * 使用線程池的好處是減少在創建和銷毀線程上所花的時間以及系統資源的開銷,解決資源不足的問題。如果不使用線程池,有可能造成系統創建大量同類線程而導致消耗完內存或則“過度切換”的問題,歸納總結就是
> * **重用存在的線程,減少對象創建、消亡的開銷,性能佳。**
> * **可有效控制最大并發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。**
> * **提供定時執行、定期執行、單線程、并發數控制等功能。**
> * Android中的線程池都是直接或間接通過配置ThreadPoolExecutor來實現不同特性的線程池.Android中最常見的類具有不同特性的線程池分別為:
> * **newCachedThreadPool**:只有非核心線程,最大線程數非常大,所有線程都活動時會為新任務創建新線程,否則會利用空閑線程 ( 60s空閑時間,過了就會被回收,所以線程池中有0個線程的可能 )來處理任務.
> * 優點:任何任務都會被立即執行(任務隊列SynchronousQuue相當于一個空集合);比較適合執行大量的耗時較少的任務.
> * **newFixedThreadPool**:只有核心線程,并且數量固定的,所有線程都活動時,因為隊列沒有限制大小,新任務會等待執行,當線程池空閑時不會釋放工作線程,還會占用一定的系統資源。
> * 優點:更快的響應外界請求
> * **newScheduledThreadPool**:核心線程數固定,非核心線程(閑著沒活干會被立即回收數)沒有限制.
> * 優點:執行定時任務以及有固定周期的重復任務
> * **newSingleThreadExecutor**:只有一個核心線程,確保所有的任務都在同一線程中按序完成
> * 優點:不需要處理線程同步的問題
> * 通過源碼可以了解到上面的四種線程池實際上還是利用 ThreadPoolExecutor 類實現的
>
> 
>
> * 推薦文章:[java線程池解析和四種線程池的使用](https://blog.csdn.net/ztchun/article/details/57413255)
#### 2、Android中還了解哪些方便線程切換的類?
> * 參考回答:
> * **AsyncTask**:底層封裝了線程池和Handler,便于執行后臺任務以及在子線程中進行UI操作。
> * **HandlerThread**:一種具有消息循環的線程,其內部可使用Handler。
> * **IntentService**:是一種異步、會自動停止的服務,內部采用HandlerThread。
#### 3、講講AsyncTask的原理
> * 參考回答:
> * **AsyncTask中有兩個線程池(SerialExecutor和THREAD\_POOL\_EXECUTOR)和一個Handler(InternalHandler),其中線程池SerialExecutor用于任務的排隊,而線程池THREAD\_POOL\_EXECUTOR用于真正地執行任務,InternalHandler用于將執行環境從線程池切換到主線程。**
> * **sHandler是一個靜態的Handler對象,為了能夠將執行環境切換到主線程,這就要求sHandler這個對象必須在主線程創建。由于靜態成員會在加載類的時候進行初始化,因此這就變相要求AsyncTask的類必須在主線程中加載,否則同一個進程中的AsyncTask都將無法正常工作。**
#### 4、IntentService有什么用 ?
> * 參考回答:
> * **IntentService**可用于**執行后臺耗時**的任務,當任務執行完成后會**自動停止**,同時由于IntentService是服務的原因,不同于普通Service,IntentService可**自動創建子線程**來執行任務,這導致它的優先級比單純的線程要高,不容易被系統殺死,所以IntentService比較適合執行一些**高優先級**的后臺任務。
#### 5、直接在Activity中創建一個thread跟在service中創建一個thread之間的區別?
> * 參考回答:
> * **在Activity中被創建**:該Thread的就是為這個Activity服務的,完成這個特定的Activity交代的任務,主動通知該Activity一些消息和事件,Activity銷毀后,該Thread也沒有存活的意義了。
> * **在Service中被創建**:這是保證最長生命周期的Thread的唯一方式,只要整個Service不退出,Thread就可以一直在后臺執行,一般在Service的onCreate()中創建,在onDestroy()中銷毀。所以,在Service中創建的Thread,適合長期執行一些獨立于APP的后臺任務,比較常見的就是:在Service中保持與服務器端的長連接。
#### 6、ThreadPoolExecutor的工作策略 ?
> * 參考回答:ThreadPoolExecutor執行任務時會遵循如下規則
> * 如果線程池中的線程數量**未達到**核心線程的數量,那么會直接啟動一個核心線程來執行任務。
> * 如果線程池中的線程數量**已經達到**或則超過核心線程的數量,那么任務會被插入任務隊列中排隊等待執行。
> * 如果在第2點無法將任務插入到任務隊列中,這往往是由于任務隊列已滿,這個時候如果在線程數量**未達到線程池規定的最大值**,那么會立刻啟動一個非核心線程來執行任務。
> * 如果第3點中線程數量**已經達到線程池規定的最大值**,那么就拒絕執行此任務,ThreadPoolExecutor會調用RejectedExecutionHandler的rejectedExecution方法來通知調用者。
#### 7、Handler、Thread和HandlerThread的差別?
> * 參考回答:
> * **Handler**:在android中負責發送和處理消息,通過它可以實現其他支線線程與主線程之間的消息通訊。
> * **Thread**:Java進程中執行運算的最小單位,亦即執行處理機調度的基本單位。某一進程中一路單獨運行的程序。
> * **HandlerThread**:一個繼承自Thread的類HandlerThread,Android中沒有對Java中的Thread進行任何封裝,而是提供了一個繼承自Thread的類HandlerThread類,這個類對Java的Thread做了很多便利的封裝。HandlerThread繼承于Thread,所以它本質就是個Thread。與普通Thread的差別就在于,它在內部直接實現了Looper的實現,這是Handler消息機制必不可少的。有了自己的looper,可以讓我們在自己的線程中分發和處理消息。如果不用HandlerThread的話,需要手動去調用Looper.prepare()和Looper.loop()這些方法。
#### 8、ThreadLocal的原理
> * 參考回答:
> * ThreadLocal是一個關于創建線程局部變量的類。使用場景如下所示:
> * **實現單個線程單例以及單個線程上下文信息存儲,比如交易id等。**
> * **實現線程安全,非線程安全的對象使用ThreadLocal之后就會變得線程安全,因為每個線程都會有一個對應的實例。 承載一些線程相關的數據,避免在方法中來回傳遞參數。**
> * 當需要使用多線程時,有個變量恰巧不需要共享,此時就不必使用synchronized這么麻煩的關鍵字來鎖住,每個線程都相當于在堆內存中開辟一個空間,線程中帶有對共享變量的緩沖區,通過緩沖區將堆內存中的共享變量進行讀取和操作,ThreadLocal相當于線程內的內存,一個局部變量。每次可以對線程自身的數據讀取和操作,并不需要通過緩沖區與 主內存中的變量進行交互。并不會像synchronized那樣修改主內存的數據,再將主內存的數據復制到線程內的工作內存。ThreadLocal可以讓線程獨占資源,存儲于線程內部,避免線程堵塞造成CPU吞吐下降。
> * 在每個Thread中包含一個ThreadLocalMap,ThreadLocalMap的key是ThreadLocal的對象,value是獨享數據。
#### 9、多線程是否一定會高效(優缺點)
> * 參考回答:
> * 多線程的優點:
> * **方便高效的內存共享 - 多進程下內存共享比較不便,且會抵消掉多進程編程的好處**
> * **較輕的上下文切換開銷 - 不用切換地址空間,不用更改CR3寄存器,不用清空TLB**
> * **線程上的任務執行完后自動銷毀**
> * 多線程的缺點:
> * **開啟線程需要占用一定的內存空間(默認情況下,每一個線程都占512KB)**
> * **如果開啟大量的線程,會占用大量的內存空間,降低程序的性能**
> * **線程越多,cpu在調用線程上的開銷就越大**
> * **程序設計更加復雜,比如線程間的通信、多線程的數據共享**
> * 綜上得出,多線程**不一定**能提高效率,在內存空間緊張的情況下反而是一種負擔,因此在日常開發中,應盡量
> * **不要頻繁創建,銷毀線程,使用線程池**
> * **減少線程間同步和通信(最為關鍵)**
> * **避免需要頻繁共享寫的數據**
> * **合理安排共享數據結構,避免偽共享(false sharing)**
> * **使用非阻塞數據結構/算法**
> * **避免可能產生可伸縮性問題的系統調用(比如mmap)**
> * **避免產生大量缺頁異常,盡量使用Huge Page**
> * **可以的話使用用戶態輕量級線程代替內核線程**
#### 10、多線程中,讓你做一個單例,你會怎么做
> * 參考回答:
> * 多線程中建立單例模式考慮的因素有很多,比如線程安全 -延遲加載-代碼安全:如防止序列化攻擊,防止反射攻擊(防止反射進行私有方法調用) -性能因素
> * 實現方法有多種,餓漢,懶漢(線程安全,線程非安全),雙重檢查(DCL),內部類,以及枚舉
>
> 
>
> * 推薦文章:[單例模式的總結](https://xxxblank.github.io/2017/09/14/singleTon/)
#### 11、除了notify還有什么方式可以喚醒線程
> * 參考回答:
> * 當一個擁有Object鎖的線程調用 wait()方法時,就會使當前線程加入object.wait 等待隊列中,并且釋放當前占用的Object鎖,這樣其他線程就有機會獲取這個Object鎖,獲得Object鎖的線程調用notify()方法,就能在Object.wait 等待隊列中隨機喚醒一個線程(該喚醒是隨機的與加入的順序無關,優先級高的被喚醒概率會高)
> * 如果調用notifyAll()方法就喚醒全部的線程。**注意:調用notify()方法后并不會立即釋放object鎖,會等待該線程執行完畢后釋放Object鎖。**
#### 12、什么是ANR ? 什么情況會出現ANR ?如何避免 ? 在不看代碼的情況下如何快速定位出現ANR問題所在 ?
> * 參考回答:
> * ANR(Application Not Responding,應用無響應):當操作在一段時間內系統無法處理時,會在系統層面會彈出ANR對話框
> * 產生ANR可能是因為5s內無響應用戶輸入事件、10s內未結束BroadcastReceiver、20s內未結束Service
> * 想要避免ANR就不要在主線程做耗時操作,而是通過開子線程,方法比如繼承Thread或實現Runnable接口、使用AsyncTask、IntentService、HandlerThread等
> * 推薦文章:[如何快速分析定位ANR](https://www.jianshu.com/p/cfa9ed42e379)