-
你在項目里都用到了那些設(shè)計模式酬屉,以及你了解知道的設(shè)計模式负懦,和運(yùn)用場景。
a. 建造者模式:將一個復(fù)雜的對象的構(gòu)建拆分缩滨,一個復(fù)雜的對象可能存在多種不同的表現(xiàn)形式势就,使用同樣的構(gòu)造過程,可以創(chuàng)建出來不同的表現(xiàn)脉漏。
比如:常見的安卓使用這種模式的有AlertDialog苞冯,在開發(fā)的例子Camera開發(fā)過程中,可能需要設(shè)置一個初始化的相機(jī)配置侧巨,設(shè)置攝像頭方向舅锄,閃光燈開閉,成像質(zhì)量等等司忱,這種場景下就可以使用建造者模式巧娱。
b.裝飾者模式:動態(tài)地給一個對象添加一些額外的職責(zé)碉怔。裝飾者可以在不改變原有類的結(jié)構(gòu)上增強(qiáng)類的功能。
比如:需要擴(kuò)展一個類的功能禁添,或給一個類增加附加功能時撮胧,可以使用裝飾者模式,這樣的話就可以使用裝飾者模式老翘,比如在項目里面封裝好的網(wǎng)絡(luò)請求芹啥,在后期開發(fā)中,需要添加新的功能铺峭,可以在向外包裝一層墓怀。
c.觀察者模式:定義對象間的一種一個對多個的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生變化的時候卫键,所有依賴它的對象都要得到通知并自動更新傀履。
比如:項目中有用到的地方可以說在網(wǎng)絡(luò)框架這里,封裝網(wǎng)絡(luò)狀態(tài)的時候莉炉,跟住不同的網(wǎng)路狀態(tài)來設(shè)置不同的功能钓账,比如WIFI,移動網(wǎng)絡(luò)絮宁,或者是無網(wǎng)絡(luò)的時候的一些處理梆暮,可以通過觀察網(wǎng)絡(luò)的狀態(tài)來實現(xiàn)。
-
說說java的線程绍昂,以及你對線程池的理解啦粹。
線程的創(chuàng)建方法
1.繼承Thread類實現(xiàn)多線程
2.實現(xiàn)Runnable接口
3.實現(xiàn)Callable接口
線程與進(jìn)程的區(qū)別
進(jìn)程包括線程,一個進(jìn)程可以有多個線程窘游,不同的進(jìn)程使用不同的內(nèi)存空間唠椭,所有的線程同享同一個內(nèi)存空間。
Java中Runnable和Callable有什么不同忍饰?
Runnable和Callable都代表著在不同線程里面執(zhí)行的任務(wù)贪嫂。Ruannable是在java1.0出來的,而Callable是在java1.5后出來的喘批,主要區(qū)別是Callable的call()方法有返回值或者拋出異常,而runnable的run()沒有這個功能铣揉。Callable可以返回裝載有計算結(jié)果的Future對象饶深。
java中的關(guān)鍵字volatile是什么
volatile關(guān)鍵字只能作用在成員變量上,被volatile修飾的變量逛拱,可以保證下一個讀取操作會在前一個寫操作之后發(fā)生敌厘。
一個線程發(fā)生異常會怎么樣?
簡單的說朽合,如果異常沒有被捕獲的話俱两,該線程就會被停止饱狂。
對于沒有捕獲的異常,我們的方法是通過給線程設(shè)置UncaughtExceptionHandler,即對未知異常的處理宪彩,這時你就可以進(jìn)行相關(guān)日志操作了.
class MyExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {//在這你可以記錄相關(guān)錯誤日志到文件中
System.out.printf("An exception has been captured\n");
System.out.printf("Thread:%s\n", t.getName());
System.out.printf("Exception: %s: %s:\n", e.getClass().getName(), e.getMessage());
System.out.printf("Stack Trace:\n");
e.printStackTrace();
System.out.printf("Thread status:%s\n", t.getState());
}
//然后把你創(chuàng)建的異常處理類休讳,設(shè)置給你的線程就可以了。
Thread thread = new Thread(new ThreadTest1());
thread.setUncaughtExceptionHandler(new MyExceptionHandler());
thread.start();
如何在多線程中共享數(shù)據(jù)
這個問題你首先要想到的是我們常舉得例子尿孔,賣票和存款的例子俊柔。
賣票的例子是做的同一個操作,也就是多個線程使用同一個runnable就可以活合。
存款的例子是讓封裝共同數(shù)據(jù)雏婶,讓共享數(shù)據(jù)成為成員變量,書寫不同的runnable白指,來調(diào)用共享類的成員變量留晚,使用像阻塞隊列這樣并發(fā)的數(shù)據(jù)結(jié)構(gòu)。用wait和notify方法可以實現(xiàn)生產(chǎn)者消費(fèi)者模型告嘲。實現(xiàn)數(shù)據(jù)的共享错维。
java中堆和棧有什么不同
每個線程都有自己的棧內(nèi)存,而多個線程共享同一個堆內(nèi)存状蜗。最主要的區(qū)別就是棧內(nèi)存用來存儲局部變量和方法調(diào)用需五。而堆內(nèi)存用來存儲Java中的對象。無論是成員變量轧坎,局部變量宏邮,還是類變量,它們指向的對象都存儲在堆內(nèi)存中缸血。
活鎖與死鎖
活鎖:優(yōu)先級相同的線程蜜氨,互相禮讓,都不執(zhí)行捎泻,最終導(dǎo)致活鎖
死鎖:多個線程需要互相等待對方的操作資源的時候飒炎,其他線程持有資源不釋放而導(dǎo)致的,常見的情況就是線程持有的鎖不同而導(dǎo)致的笆豁。其實就是互相不禮讓郎汪,最終導(dǎo)致死鎖。
餓死:有一個線程一直禮讓闯狱,最終導(dǎo)致這個線程的任務(wù)一直不執(zhí)行煞赢。
單例模式的雙檢鎖問題
public class Singleton {
//正確的是加上 volatile關(guān)鍵字 private static volatile Singleton uniqueInstance;
private static Singleton uniqueInstance;
private Singleton(){
}
public static Singleton getInstance(){
if(uniqueInstance == null){ //#1
synchronized(Singleton.class){ //#2
if(uniqueInstance == null){ //#3
uniqueInstance = new Singleton(); //#4
System.out.println(Thread.currentThread().getName() + ": uniqueInstance is initalized..."); //#5.1
} else {
System.out.println(Thread.currentThread().getName() + ": uniqueInstance is not null now..."); //#5.2
}
}
}
return uniqueInstance;
}
}
情況假如線程1進(jìn)來,走到#1哄孤,判斷實例為空照筑,讓出cpu的執(zhí)行權(quán)給線程2.
線程2進(jìn)來執(zhí)行#1 判斷為空,讓出cpu的執(zhí)行權(quán),給線程1凝危。
線程1一直走到#2波俄,#3,#4蛾默,出去懦铺,線程2進(jìn)來,由于線程2在#1中持有的實例為空趴生,所以也就會走#2阀趴,#3,#4.從而創(chuàng)建出兩個對象苍匆。
加上volatile后刘急,這個關(guān)鍵字可以及時更新每個線程里面的數(shù)據(jù)變化,也就是可以保證下一個讀取操作會在前一個寫操作之后發(fā)生浸踩。
什么是線程池叔汁,如何使用
- 什么是線程池:java提供了Executor接口的實現(xiàn)用于創(chuàng)建線程池,線程池主要是用來管理線程的检碗。
其中有四個常用的線程池
①newSingleThreadExecutor
單個線程的線程池据块,即線程池中每次只有一個線程工作,單線程串行執(zhí)行任務(wù)
②newFixedThreadExecutor(n)
固定數(shù)量的線程池折剃,沒提交一個任務(wù)就是一個線程另假,直到達(dá)到線程池的最大數(shù)量,然后后面進(jìn)入等待隊列直到前面的任務(wù)完成才繼續(xù)執(zhí)行
③newCacheThreadExecutor(推薦使用)
可緩存線程池怕犁,當(dāng)線程池大小超過了處理任務(wù)所需的線程边篮,那么就會回收部分空閑(一般是60秒無執(zhí)行)的線程,當(dāng)有任務(wù)來時奏甫,又智能的添加新線程來執(zhí)行戈轿。
④newScheduleThreadExecutor
大小無限制的線程池,支持定時和周期性的執(zhí)行線程
線程池的工作原理
線程池可以減少創(chuàng)建和銷毀線程的次數(shù)阵子,從而減少系統(tǒng)資源的消耗思杯,當(dāng)一個任務(wù)提交到線程池時
a. 首先判斷核心線程池中的線程是否已經(jīng)滿了,如果沒滿挠进,則創(chuàng)建一個核心線程執(zhí)行任務(wù)色乾,否則進(jìn)入下一步
b. 判斷工作隊列是否已滿,沒有滿則加入工作隊列领突,否則執(zhí)行下一步
c. 判斷線程數(shù)是否達(dá)到了最大值暖璧,如果不是,則創(chuàng)建非核心線程執(zhí)行
任務(wù)攘须,否則執(zhí)行飽和策略漆撞,默認(rèn)拋出異常
結(jié)合項目的例子:多張圖片的上傳,在使用線程池后可以減少上傳的時間于宙。原本上傳需要9秒浮驳,用線程池后需要2秒。
-
內(nèi)存泄漏問題
- 非靜態(tài)內(nèi)部類造成的內(nèi)存泄漏
非靜態(tài)的內(nèi)部類會持有外部類的指引捞魁,當(dāng)在內(nèi)部類中做一些不可控制生命周期的操作就有可能會產(chǎn)生內(nèi)存泄漏至会,比如在線程中執(zhí)行耗時操作就有可能發(fā)生內(nèi)存泄漏,導(dǎo)致外部類無法被回收谱俭,直到耗時任務(wù)結(jié)束奉件,解決辦法是在頁面退出時結(jié)束線程中的任務(wù) - 非靜態(tài)內(nèi)部類的靜態(tài)實例造成的內(nèi)存泄漏。
非靜態(tài)內(nèi)部類會持有外部類的指引昆著,如果非靜態(tài)內(nèi)部類的靜態(tài)實例县貌,就會長期持有外部類的指引,這樣外部類就不會被系統(tǒng)回收凑懂,解決方法是把非靜態(tài)內(nèi)部類寫成靜態(tài)內(nèi)部類煤痕。 - handler內(nèi)存泄漏
handler也是非靜態(tài)內(nèi)部類造成的內(nèi)存泄漏幌缝,因為handler內(nèi)部有一個MessageQueue用來存放message狞悲,有些message不能被及時處理會長時間存在于內(nèi)存中唱星,導(dǎo)致handler無法被回收徽千,如果handler屬于非靜態(tài)內(nèi)部類萝玷,所以持有外部類的指引符匾,導(dǎo)致外部類不能被回收往湿,解決方法1.使用靜態(tài)handler研侣,外部類引用使用弱引用處理2.在退出頁面時移除消息隊列中的消息扫夜。 - Context導(dǎo)致的內(nèi)存泄漏
跟住場景需要使用Activity還是Application的Context楞泼,因為他們的生命周期不一樣,一些不需要使用Activity的Context的地方就換成Application的Context历谍。最常見的就是單例傳入的上下文引起的內(nèi)存泄漏现拒,比如傳入一個Activity的Context被靜態(tài)類引用,導(dǎo)致無法回收望侈。 - 靜態(tài)View引起的內(nèi)存泄漏
使用靜態(tài)View可以避免每次啟動Activity都去讀取并渲染View印蔬,但是靜態(tài)View會持有Activity的引用,導(dǎo)致無法回收脱衙,解決辦法是在Activity銷毀的時候?qū)㈧o態(tài)View設(shè)置為null(View一旦被加載到界面中將會持有一個Context對象的引用侥猬,在這個例子中,這個context對象是我們的Activity捐韩,聲明一個靜態(tài)變量引用這個View退唠,也就引用了activity) - 資源對象未關(guān)閉導(dǎo)致的內(nèi)存泄漏
file,Cursor荤胁,內(nèi)部都設(shè)置了緩存瞧预,在不適用的時候一定要關(guān)閉。 - bitmap造成的內(nèi)存泄漏
bitmap是比較占內(nèi)存的,所以一定要在不使用的時候及時進(jìn)行清理垢油,避免靜態(tài)變量持有大的bitmap對象 - 集合造成的內(nèi)存泄漏
集合用于保存對象盆驹,如果集合越來越大,不進(jìn)行合理的清理滩愁,尤其是入股集合是靜態(tài)的 - 監(jiān)聽器未關(guān)閉造成的內(nèi)存泄漏
注冊的廣播啊躯喇,服務(wù)啊等,不用的時候一定要取消掉硝枉。
-
onRestart的調(diào)用場景
按home鍵后再回到界面
從A界面跳到B界面廉丽,又按返回鍵返回A界面
從本Activity切換到其他的應(yīng)用,然后再從其他應(yīng)用切換回來妻味,會調(diào)用onRestart()正压;
-
橫豎屏切換時生命周期
1、不設(shè)置Activity的android:configChanges時责球,切屏?xí)匦抡{(diào)用各個生命周期蔑匣,切橫屏?xí)r會執(zhí)行一次,切豎屏?xí)r會執(zhí)行兩次
2棕诵、設(shè)置Activity的android:configChanges="orientation"時裁良,切屏還是會重新調(diào)用各個生命周期,切橫校套、豎屏?xí)r只會執(zhí)行一次
3价脾、設(shè)置Activity的android:configChanges="orientation|keyboardHidden"時,切屏不會重新調(diào)用各個生命周期笛匙,只會執(zhí)行onConfigurationChanged方法
-
SurfaceView與View的區(qū)別侨把。
- View是底層單緩沖機(jī)制,SurfaceView是雙緩沖機(jī)制
- View主要試用于主動更新妹孙,SurfaceView適用于被動更新秋柄,頻繁更新。
3 .View的繪制是在UI主線程蠢正,SurfaceView的繪制是單獨(dú)開一個線程骇笔。
SurfaceView的內(nèi)容不在應(yīng)用窗口上,所以不能使用變換(平移嚣崭、縮放笨触、旋轉(zhuǎn)等)。也難以放在ListView或者ScrollView中雹舀,不能使用UI控件的一些特性比如View.setAlpha()
View:顯示視圖芦劣,內(nèi)置畫布,提供圖形繪制函數(shù)说榆、觸屏事件虚吟、按鍵事件函數(shù)等寸认;必須在UI主線程內(nèi)更新畫面,速度較慢串慰。
SurfaceView:基于view視圖進(jìn)行拓展的視圖類废麻,更適合2D游戲的開發(fā);是view的子類模庐,類似使用雙緩機(jī)制,在新的線程中更新畫面所以刷新界面速度比view快油宜,Camera預(yù)覽界面使用SurfaceView掂碱。
-
Android 中的線程有那些,原理與各自特點
-
ANR的原因
1.耗時的網(wǎng)絡(luò)訪問
2.大量的數(shù)據(jù)讀寫
3.數(shù)據(jù)庫操作
4.硬件操作(比如camera)
5.調(diào)用thread的join()方法、sleep()方法慎冤、wait()方法或者等待線程鎖的時候
6.service binder的數(shù)量達(dá)到上限
7.system server中發(fā)生WatchDog ANR
8.service忙導(dǎo)致超時無響應(yīng)
9.其他線程持有鎖疼燥,導(dǎo)致主線程等待超時
10.其它線程終止或崩潰導(dǎo)致主線程一直等待