java相關(guān)基礎(chǔ)知識(shí)
1、java中==和equals和hashCode的區(qū)別
基本數(shù)據(jù)類型的==比較的值相等.
類的==比較的內(nèi)存的地址,即是否是同一個(gè)對(duì)象,在不覆蓋equals的情況下,同比較內(nèi)存地址,原實(shí)現(xiàn)也為 == ,如String等重寫了equals方法.
hashCode也是Object類的一個(gè)方法。返回一個(gè)離散的int型整數(shù)。在集合類操作中使用,為了提高查詢速度。(HashMap,HashSet等比較是否為同一個(gè))
如果兩個(gè)對(duì)象equals,Java運(yùn)行時(shí)環(huán)境會(huì)認(rèn)為他們的hashcode一定相等。
如果兩個(gè)對(duì)象不equals,他們的hashcode有可能相等。
如果兩個(gè)對(duì)象hashcode相等,他們不一定equals。
如果兩個(gè)對(duì)象hashcode不相等,他們一定不equals。
2、int與integer的區(qū)別
int 基本類型
integer 對(duì)象 int的封裝類
3、關(guān)鍵字final和static是怎么使用的。
final:
1、final變量即為常量,只能賦值一次。
2、final方法不能被子類重寫。
3、final類不能被繼承。
static:
1、static變量:對(duì)于靜態(tài)變量在內(nèi)存中只有一個(gè)拷貝(節(jié)省內(nèi)存),JVM只為靜態(tài)分配一次內(nèi)存,在加載類的過(guò)程中完成靜態(tài)變量的內(nèi)存分配,可用類名直接訪問(wèn)(方便),當(dāng)然也可以通過(guò)對(duì)象來(lái)訪問(wèn)(但是這是不推薦的)。
2、static代碼塊:static代碼塊是類加載時(shí),初始化自動(dòng)執(zhí)行的。
3、static方法:static方法可以直接通過(guò)類名調(diào)用,任何的實(shí)例也都可以調(diào)用,因此static方法中不能用this和super關(guān)鍵字,不能直接訪問(wèn)所屬類的實(shí)例變量和實(shí)例方法(就是不帶static的成員變量和成員成員方法),只能訪問(wèn)所屬類的靜態(tài)成員變量和成員方法。
4、String,StringBuffer,StringBuilder區(qū)別
String:字符串常量 不適用于經(jīng)常要改變值得情況,每次改變相當(dāng)于生成一個(gè)新的對(duì)象
StringBuffer:字符串變量(線程安全)
StringBuilder:字符串變量(線程不安全) 確保單線程下可用,效率略高于StringBuffer
1、三者在執(zhí)行速度上:StringBuilder > StringBuffer > String (由于String是常量,不可改變,拼接時(shí)會(huì)重新創(chuàng)建新的對(duì)象)。
2、StringBuffer是線程安全的,StringBuilder是線程不安全的。(由于StringBuffer有緩沖區(qū))
5、Java中重載和重寫的區(qū)別:
1、重載:一個(gè)類中可以有多個(gè)相同方法名的,但是參數(shù)類型和個(gè)數(shù)都不一樣。這是重載。
2、重寫:子類繼承父類,則子類可以通過(guò)實(shí)現(xiàn)父類中的方法,從而新的方法把父類舊的方法覆蓋。
6、什么是內(nèi)部類??jī)?nèi)部類的作用
內(nèi)部類可直接訪問(wèn)外部類的屬性
Java中內(nèi)部類主要分為成員內(nèi)部類、局部?jī)?nèi)部類(嵌套在方法和作用域內(nèi))、匿名內(nèi)部類(沒(méi)構(gòu)造方法)、靜態(tài)內(nèi)部類(static修飾的類,不能使用任何外圍類的非static成員變量和方法, 不依賴外圍類)
7、Serializable 和Parcelable 的區(qū)別
Serializable Java 序列化接口 在硬盤上讀寫 讀寫過(guò)程中有大量臨時(shí)變量的生成,內(nèi)部執(zhí)行大量的i/o操作,效率很低。
Parcelable Android 序列化接口 效率高 使用麻煩 在內(nèi)存中讀寫(AS有相關(guān)插件 一鍵生成所需方法) ,對(duì)象不能保存到磁盤中
8、靜態(tài)屬性和靜態(tài)方法是否可以被繼承?是否可以被重寫?以及原因?
可繼承 不可重寫 而是被隱藏
如果子類里面定義了靜態(tài)方法和屬性,那么這時(shí)候父類的靜態(tài)方法或?qū)傩苑Q之為"隱藏"。如果你想要調(diào)用父類的靜態(tài)方法和屬性,直接通過(guò)父類名.方法或變量名完成。
9、成員內(nèi)部類、靜態(tài)內(nèi)部類、局部?jī)?nèi)部類和匿名內(nèi)部類的理解,以及項(xiàng)目中的應(yīng)用
ava中內(nèi)部類主要分為成員內(nèi)部類、局部?jī)?nèi)部類(嵌套在方法和作用域內(nèi))、匿名內(nèi)部類(沒(méi)構(gòu)造方法)、靜態(tài)內(nèi)部類(static修飾的類,不能使用任何外圍類的非static成員變量和方法, 不依賴外圍類)
使用內(nèi)部類最吸引人的原因是:每個(gè)內(nèi)部類都能獨(dú)立地繼承一個(gè)(接口的)實(shí)現(xiàn),所以無(wú)論外圍類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn),對(duì)于內(nèi)部類都沒(méi)有影響。
因?yàn)镴ava不支持多繼承,支持實(shí)現(xiàn)多個(gè)接口。但有時(shí)候會(huì)存在一些使用接口很難解決的問(wèn)題,這個(gè)時(shí)候我們可以利用內(nèi)部類提供的、可以繼承多個(gè)具體的或者抽象的類的能力來(lái)解決這些程序設(shè)計(jì)問(wèn)題??梢赃@樣說(shuō),接口只是解決了部分問(wèn)題,而內(nèi)部類使得多重繼承的解決方案變得更加完整。
10、string 轉(zhuǎn)換成 integer的方式及原理
String ?integer Intrger.parseInt(string);
Integer?string Integer.toString();
11、哪些情況下的對(duì)象會(huì)被垃圾回收機(jī)制處理掉?
1.所有實(shí)例都沒(méi)有活動(dòng)線程訪問(wèn)。
2.沒(méi)有被其他任何實(shí)例訪問(wèn)的循環(huán)引用實(shí)例。
3.Java 中有不同的引用類型。判斷實(shí)例是否符合垃圾收集的條件都依賴于它的引用類型。
要判斷怎樣的對(duì)象是沒(méi)用的對(duì)象。這里有2種方法:
1.采用標(biāo)記計(jì)數(shù)的方法:
給內(nèi)存中的對(duì)象給打上標(biāo)記,對(duì)象被引用一次,計(jì)數(shù)就加1,引用被釋放了,計(jì)數(shù)就減一,當(dāng)這個(gè)計(jì)數(shù)為0的時(shí)候,這個(gè)對(duì)象就可以被回收了。當(dāng)然,這也就引發(fā)了一個(gè)問(wèn)題:循環(huán)引用的對(duì)象是無(wú)法被識(shí)別出來(lái)并且被回收的。所以就有了第二種方法:
2.采用根搜索算法:
從一個(gè)根出發(fā),搜索所有的可達(dá)對(duì)象,這樣剩下的那些對(duì)象就是需要被回收的
12、靜態(tài)代理和動(dòng)態(tài)代理的區(qū)別,什么場(chǎng)景使用?
靜態(tài)代理類:
由程序員創(chuàng)建或由特定工具自動(dòng)生成源代碼,再對(duì)其編譯。在程序運(yùn)行前,代理類的.class文件就已經(jīng)存在了。動(dòng)態(tài)代理類:在程序運(yùn)行時(shí),運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。
13、Java中實(shí)現(xiàn)多態(tài)的機(jī)制是什么?
答:方法的重寫Overriding和重載Overloading是Java多態(tài)性的不同表現(xiàn)
重寫Overriding是父類與子類之間多態(tài)性的一種表現(xiàn)
重載Overloading是一個(gè)類中多態(tài)性的一種表現(xiàn).
14、說(shuō)說(shuō)你對(duì)Java反射的理解
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中, 對(duì)于任意一個(gè)類, 都能夠知道這個(gè)類的所有屬性和方法; 對(duì)于任意一個(gè)對(duì)象, 都能夠調(diào)用它的任意一個(gè)方法和屬性。 從對(duì)象出發(fā),通過(guò)反射(Class類)可以取得取得類的完整信息(類名 Class類型,所在包、具有的所有方法 Method[]類型、某個(gè)方法的完整信息(包括修飾符、返回值類型、異常、參數(shù)類型)、所有屬性 Field[]、某個(gè)屬性的完整信息、構(gòu)造器 Constructors),調(diào)用類的屬性或方法自己的總結(jié): 在運(yùn)行過(guò)程中獲得類、對(duì)象、方法的所有信息。
15、說(shuō)說(shuō)你對(duì)Java注解的理解
元注解
元注解的作用就是負(fù)責(zé)注解其他注解。java5.0的時(shí)候,定義了4個(gè)標(biāo)準(zhǔn)的meta-annotation類型,它們用來(lái)提供對(duì)其他注解的類型作說(shuō)明。
1.@Target
2.@Retention
3.@Documented
4.@Inherited
16、Java中String的了解和String為什么要設(shè)計(jì)成不可變的?
在源碼中string是用final 進(jìn)行修飾,它是不可更改,不可繼承的常量。
1、字符串池的需求
字符串池是方法區(qū)(Method Area)中的一塊特殊的存儲(chǔ)區(qū)域。當(dāng)一個(gè)字符串已經(jīng)被創(chuàng)建并且該字符串在 池 中,該字符串的引用會(huì)立即返回給變量,而不是重新創(chuàng)建一個(gè)字符串再將引用返回給變量。如果字符串不是不可變的,那么改變一個(gè)引用(如: string2)的字符串將會(huì)導(dǎo)致另一個(gè)引用(如: string1)出現(xiàn)臟數(shù)據(jù)。
2、允許字符串緩存哈希碼
在java中常常會(huì)用到字符串的哈希碼,例如: HashMap 。String的不變性保證哈希碼始終一,因此,他可以不用擔(dān)心變化的出現(xiàn)。 這種方法意味著不必每次使用時(shí)都重新計(jì)算一次哈希碼——這樣,效率會(huì)高很多。
3、安全
String廣泛的用于java 類中的參數(shù),如:網(wǎng)絡(luò)連接(Network connetion),打開文件(opening files )等等。如果String不是不可變的,網(wǎng)絡(luò)連接、文件將會(huì)被改變——這將會(huì)導(dǎo)致一系列的安全威脅。操作的方法本以為連接上了一臺(tái)機(jī)器,但實(shí)際上卻不是。由于反射中的參數(shù)都是字符串,同樣,也會(huì)引起一系列的安全問(wèn)題。
17、Object類的equal和hashCode方法重寫,為什么?
首先equals與hashcode間的關(guān)系是這樣的:
1、如果兩個(gè)對(duì)象相同(即用equals比較返回true),那么它們的hashCode值一定要相同;
2、如果兩個(gè)對(duì)象的hashCode相同,它們并不一定相同(即用equals比較返回false)
由于為了提高程序的效率才實(shí)現(xiàn)了hashcode方法,先進(jìn)行hashcode的比較,如果不同,那沒(méi)就不必在進(jìn)行equals的比較了,這樣就大大減少了equals比較的次數(shù),這對(duì)比需要比較的數(shù)量很大的效率提高是很明顯的
18、List,Set,Map的區(qū)別
Set是最簡(jiǎn)單的一種集合。集合中的對(duì)象不按特定的方式排序,并且沒(méi)有重復(fù)對(duì)象。 Set接口主要實(shí)現(xiàn)了兩個(gè)實(shí)現(xiàn)類:HashSet: HashSet類按照哈希算法來(lái)存取集合中的對(duì)象,存取速度比較快
TreeSet :TreeSet類實(shí)現(xiàn)了SortedSet接口,能夠?qū)现械膶?duì)象進(jìn)行排序。
List的特征是其元素以線性方式存儲(chǔ),集合中可以存放重復(fù)對(duì)象。
ArrayList() : 代表長(zhǎng)度可以改變得數(shù)組。可以對(duì)元素進(jìn)行隨機(jī)的訪問(wèn),向ArrayList()中插入與刪除元素的速度慢。
LinkedList(): 在實(shí)現(xiàn)中采用鏈表數(shù)據(jù)結(jié)構(gòu)。插入和刪除速度快,訪問(wèn)速度慢。
Map 是一種把鍵對(duì)象和值對(duì)象映射的集合,它的每一個(gè)元素都包含一對(duì)鍵對(duì)象和值對(duì)象。 Map沒(méi)有繼承于Collection接口 從Map集合中檢索元素時(shí),只要給出鍵對(duì)象,就會(huì)返回對(duì)應(yīng)的值對(duì)象。
HashMap:Map基于散列表的實(shí)現(xiàn)。插入和查詢“鍵值對(duì)”的開銷是固定的??梢酝ㄟ^(guò)構(gòu)造器設(shè)置容量capacity和負(fù)載因子load factor,以調(diào)整容器的性能。
LinkedHashMap: 類似于HashMap,但是迭代遍歷它時(shí),取得“鍵值對(duì)”的順序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一點(diǎn)。而在迭代訪問(wèn)時(shí)發(fā)而更快,因?yàn)樗褂面湵砭S護(hù)內(nèi)部次序。
TreeMap : 基于紅黑樹數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)。查看“鍵”或“鍵值對(duì)”時(shí),它們會(huì)被排序(次序由Comparabel或Comparator決定)。TreeMap的特點(diǎn)在 于,你得到的結(jié)果是經(jīng)過(guò)排序的。TreeMap是唯一的帶有subMap()方法的Map,它可以返回一個(gè)子樹。
WeakHashMao :弱鍵(weak key)Map,Map中使用的對(duì)象也被允許釋放: 這是為解決特殊問(wèn)題設(shè)計(jì)的。如果沒(méi)有map之外的引用指向某個(gè)“鍵”,則此“鍵”可以被垃圾收集器回收。
19、ArrayMap和HashMap的對(duì)比
1、存儲(chǔ)方式不同
HashMap內(nèi)部有一個(gè)HashMapEntry<K, V>[]對(duì)象,每一個(gè)鍵值對(duì)都存儲(chǔ)在這個(gè)對(duì)象里,當(dāng)使用put方法添加鍵值對(duì)時(shí),就會(huì)new一個(gè)HashMapEntry對(duì)象,
2、添加數(shù)據(jù)時(shí)擴(kuò)容時(shí)的處理不一樣,進(jìn)行了new操作,重新創(chuàng)建對(duì)象,開銷很大。ArrayMap用的是copy數(shù)據(jù),所以效率相對(duì)要高。
3、ArrayMap提供了數(shù)組收縮的功能,在clear或remove后,會(huì)重新收縮數(shù)組,是否空間
4、ArrayMap采用二分法查找;
20、HashMap和HashTable的區(qū)別
1 HashMap不是線程安全的,效率高一點(diǎn)、方法不是Synchronize的要提供外同步,有containsvalue和containsKey方法。
hashtable是,線程安全,不允許有null的鍵和值,效率稍低,方法是是Synchronize的。有contains方法方法。Hashtable 繼承于Dictionary 類
21、HashMap與HashSet的區(qū)別
hashMap:HashMap實(shí)現(xiàn)了Map接口,HashMap儲(chǔ)存鍵值對(duì),使用put()方法將元素放入map中,HashMap中使用鍵對(duì)象來(lái)計(jì)算hashcode值,HashMap比較快,因?yàn)槭鞘褂梦ㄒ坏逆I來(lái)獲取對(duì)象。
HashSet實(shí)現(xiàn)了Set接口,HashSet僅僅存儲(chǔ)對(duì)象,使用add()方法將元素放入set中,HashSet使用成員對(duì)象來(lái)計(jì)算hashcode值,對(duì)于兩個(gè)對(duì)象來(lái)說(shuō)hashcode可能相同,所以equals()方法用來(lái)判斷對(duì)象的相等性,如果兩個(gè)對(duì)象不同的話,那么返回false。HashSet較HashMap來(lái)說(shuō)比較慢。
22、HashSet與HashMap怎么判斷集合元素重復(fù)?
HashSet不能添加重復(fù)的元素,當(dāng)調(diào)用add(Object)方法時(shí)候,
首先會(huì)調(diào)用Object的hashCode方法判hashCode是否已經(jīng)存在,如不存在則直接插入元素;如果已存在則調(diào)用Object對(duì)象的equals方法判斷是否返回true,如果為true則說(shuō)明元素已經(jīng)存在,如為false則插入元素。
23、ArrayList和LinkedList的區(qū)別,以及應(yīng)用場(chǎng)景
ArrayList是基于數(shù)組實(shí)現(xiàn)的,ArrayList線程不安全。
LinkedList是基于雙鏈表實(shí)現(xiàn)的:
使用場(chǎng)景:
(1)如果應(yīng)用程序?qū)Ω鱾€(gè)索引位置的元素進(jìn)行大量的存取或刪除操作,ArrayList對(duì)象要遠(yuǎn)優(yōu)于LinkedList對(duì)象;
(2)如果應(yīng)用程序主要是對(duì)列表進(jìn)行循環(huán),并且循環(huán)時(shí)候進(jìn)行插入或者刪除操作,LinkedList對(duì)象要遠(yuǎn)優(yōu)于ArrayList對(duì)象;
24、數(shù)組和鏈表的區(qū)別
數(shù)組:是將元素在內(nèi)存中連續(xù)存儲(chǔ)的;它的優(yōu)點(diǎn):因?yàn)閿?shù)據(jù)是連續(xù)存儲(chǔ)的,內(nèi)存地址連續(xù),所以在查找數(shù)據(jù)的時(shí)候效率比較高;它的缺點(diǎn):在存儲(chǔ)之前,我們需要申請(qǐng)一塊連續(xù)的內(nèi)存空間,并且在編譯的時(shí)候就必須確定好它的空間的大小。在運(yùn)行的時(shí)候空間的大小是無(wú)法隨著你的需要進(jìn)行增加和減少而改變的,當(dāng)數(shù)據(jù)兩比較大的時(shí)候,有可能會(huì)出現(xiàn)越界的情況,數(shù)據(jù)比較小的時(shí)候,又有可能會(huì)浪費(fèi)掉內(nèi)存空間。在改變數(shù)據(jù)個(gè)數(shù)時(shí),增加、插入、刪除數(shù)據(jù)效率比較低。
鏈表:是動(dòng)態(tài)申請(qǐng)內(nèi)存空間,不需要像數(shù)組需要提前申請(qǐng)好內(nèi)存的大小,鏈表只需在用的時(shí)候申請(qǐng)就可以,根據(jù)需要來(lái)動(dòng)態(tài)申請(qǐng)或者刪除內(nèi)存空間,對(duì)于數(shù)據(jù)增加和刪除以及插入比數(shù)組靈活。還有就是鏈表中數(shù)據(jù)在內(nèi)存中可以在任意的位置,通過(guò)應(yīng)用來(lái)關(guān)聯(lián)數(shù)據(jù)(就是通過(guò)存在元素的指針來(lái)聯(lián)系)
25、開啟線程的三種方式?
有三種創(chuàng)建線程的方式,分別是繼承Thread類、實(shí)現(xiàn)Runable接口和使用線程池
26、線程和進(jìn)程的區(qū)別?
線程是進(jìn)程的子集,一個(gè)進(jìn)程可以有很多線程,每條線程并行執(zhí)行不同的任務(wù)。不同的進(jìn)程使用不同的內(nèi)存空間,而所有的線程共享一片相同的內(nèi)存空間。別把它和棧內(nèi)存搞混,每個(gè)線程都擁有單獨(dú)的棧內(nèi)存用來(lái)存儲(chǔ)本地?cái)?shù)據(jù)。
27、run()和start()方法區(qū)別
這個(gè)問(wèn)題經(jīng)常被問(wèn)到,但還是能從此區(qū)分出面試者對(duì)Java線程模型的理解程度。start()方法被用來(lái)啟動(dòng)新創(chuàng)建的線程,而且start()內(nèi)部調(diào)用了run()方法,這和直接調(diào)用run()方法的效果不一樣。當(dāng)你調(diào)用run()方法的時(shí)候,只會(huì)是在原來(lái)的線程中調(diào)用,沒(méi)有新的線程啟動(dòng),start()方法才會(huì)啟動(dòng)新線程。
28、如何控制某個(gè)方法允許并發(fā)訪問(wèn)線程的個(gè)數(shù)?
semaphore.acquire() 請(qǐng)求一個(gè)信號(hào)量,這時(shí)候的信號(hào)量個(gè)數(shù)-1(一旦沒(méi)有可使用的信號(hào)量,也即信號(hào)量個(gè)數(shù)變?yōu)樨?fù)數(shù)時(shí),再次請(qǐng)求的時(shí)候就會(huì)阻塞,直到其他線程釋放了信號(hào)量)
semaphore.release() 釋放一個(gè)信號(hào)量,此時(shí)信號(hào)量個(gè)數(shù)+1
29、在Java中wait和seelp方法的不同
Java程序中wait 和 sleep都會(huì)造成某種形式的暫停,它們可以滿足不同的需要。wait()方法用于線程間通信,如果等待條件為真且其它線程被喚醒時(shí)它會(huì)釋放鎖,而sleep()方法僅僅釋放CPU資源或者讓當(dāng)前線程停止執(zhí)行一段時(shí)間,但不會(huì)釋放鎖。
30、談?wù)剋ait/notify關(guān)鍵字的理解
等待對(duì)象的同步鎖,需要獲得該對(duì)象的同步鎖才可以調(diào)用這個(gè)方法,否則編譯可以通過(guò),但運(yùn)行時(shí)會(huì)收到一個(gè)異常:IllegalMonitorStateException。
調(diào)用任意對(duì)象的 wait() 方法導(dǎo)致該線程阻塞,該線程不可繼續(xù)執(zhí)行,并且該對(duì)象上的鎖被釋放。
喚醒在等待該對(duì)象同步鎖的線程(只喚醒一個(gè),如果有多個(gè)在等待),注意的是在調(diào)用此方法的時(shí)候,并不能確切的喚醒某一個(gè)等待狀態(tài)的線程,而是由JVM確定喚醒哪個(gè)線程,而且不是按優(yōu)先級(jí)。
調(diào)用任意對(duì)象的notify()方法則導(dǎo)致因調(diào)用該對(duì)象的 wait()方法而阻塞的線程中隨機(jī)選擇的一個(gè)解除阻塞(但要等到獲得鎖后才真正可執(zhí)行)。
31、什么導(dǎo)致線程阻塞?線程如何關(guān)閉?
阻塞式方法是指程序會(huì)一直等待該方法完成期間不做其他事情,ServerSocket的accept()方法就是一直等待客戶端連接。這里的阻塞是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起,直到得到結(jié)果之后才會(huì)返回。此外,還有異步和非阻塞式方法在任務(wù)完成前就返回。
一種是調(diào)用它里面的stop()方法
另一種就是你自己設(shè)置一個(gè)停止線程的標(biāo)記 (推薦這種)
32、如何保證線程安全?
1.synchronized;
2.Object方法中的wait,notify;
3.ThreadLocal機(jī)制 來(lái)實(shí)現(xiàn)的。
33、如何實(shí)現(xiàn)線程同步?
1、synchronized關(guān)鍵字修改的方法。
2、synchronized關(guān)鍵字修飾的語(yǔ)句塊3、使用特殊域變量(volatile)實(shí)現(xiàn)線程同步
34、線程間操作List
List list = Collections.synchronizedList(new ArrayList());
35、談?wù)剬?duì)Synchronized關(guān)鍵字,類鎖,方法鎖,重入鎖的理解
java的對(duì)象鎖和類鎖:java的對(duì)象鎖和類鎖在鎖的概念上基本上和內(nèi)置鎖是一致的,但是,兩個(gè)鎖實(shí)際是有很大的區(qū)別的,對(duì)象鎖是用于對(duì)象實(shí)例方法,或者一個(gè)對(duì)象實(shí)例上的,類鎖是用于類的靜態(tài)方法或者一個(gè)類的class對(duì)象上的。我們知道,類的對(duì)象實(shí)例可以有很多個(gè),但是每個(gè)類只有一個(gè)class對(duì)象,所以不同對(duì)象實(shí)例的對(duì)象鎖是互不干擾的,但是每個(gè)類只有一個(gè)類鎖。但是有一點(diǎn)必須注意的是,其實(shí)類鎖只是一個(gè)概念上的東西,并不是真實(shí)存在的,它只是用來(lái)幫助我們理解鎖定實(shí)例方法和靜態(tài)方法的區(qū)別的
36、synchronized 和volatile 關(guān)鍵字的區(qū)別
1.volatile本質(zhì)是在告訴jvm當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的,需要從主存中讀??;synchronized則是鎖定當(dāng)前變量,只有當(dāng)前線程可以訪問(wèn)該變量,其他線程被阻塞住。
2.volatile僅能使用在變量級(jí)別;synchronized則可以使用在變量、方法、和類級(jí)別的
3.volatile僅能實(shí)現(xiàn)變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性
4.volatile不會(huì)造成線程的阻塞;synchronized可能會(huì)造成線程的阻塞。
5.volatile標(biāo)記的變量不會(huì)被編譯器優(yōu)化;synchronized標(biāo)記的變量可以被編譯器優(yōu)化
37、ReentrantLock 、synchronized和volatile比較
ava在過(guò)去很長(zhǎng)一段時(shí)間只能通過(guò)synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)互斥,它有一些缺點(diǎn)。比如你不能擴(kuò)展鎖之外的方法或者塊邊界,嘗試獲取鎖時(shí)不能中途取消等。Java 5 通過(guò)Lock接口提供了更復(fù)雜的控制來(lái)解決這些問(wèn)題。 ReentrantLock 類實(shí)現(xiàn)了 Lock,它擁有與 synchronized 相同的并發(fā)性和內(nèi)存語(yǔ)義且它還具有可擴(kuò)展性。
38、死鎖的四個(gè)必要條件?
死鎖產(chǎn)生的原因
- 系統(tǒng)資源的競(jìng)爭(zhēng)
系統(tǒng)資源的競(jìng)爭(zhēng)導(dǎo)致系統(tǒng)資源不足,以及資源分配不當(dāng),導(dǎo)致死鎖。
- 進(jìn)程運(yùn)行推進(jìn)順序不合適
互斥條件:一個(gè)資源每次只能被一個(gè)進(jìn)程使用,即在一段時(shí)間內(nèi)某 資源僅為一個(gè)進(jìn)程所占有。此時(shí)若有其他進(jìn)程請(qǐng)求該資源,則請(qǐng)求進(jìn)程只能等待。
請(qǐng)求與保持條件:進(jìn)程已經(jīng)保持了至少一個(gè)資源,但又提出了新的資源請(qǐng)求,而該資源 已被其他進(jìn)程占有,此時(shí)請(qǐng)求進(jìn)程被阻塞,但對(duì)自己已獲得的資源保持不放。
不可剝奪條件:進(jìn)程所獲得的資源在未使用完畢之前,不能被其他進(jìn)程強(qiáng)行奪走,即只能 由獲得該資源的進(jìn)程自己來(lái)釋放(只能是主動(dòng)釋放)。
循環(huán)等待條件: 若干進(jìn)程間形成首尾相接循環(huán)等待資源的關(guān)系
這四個(gè)條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會(huì)發(fā)生死鎖。
死鎖的避免與預(yù)防:
死鎖避免的基本思想:
系統(tǒng)對(duì)進(jìn)程發(fā)出每一個(gè)系統(tǒng)能夠滿足的資源申請(qǐng)進(jìn)行動(dòng)態(tài)檢查,并根據(jù)檢查結(jié)果決定是否分配資源,如果分配后系統(tǒng)可能發(fā)生死鎖,則不予分配,否則予以分配。這是一種保證系統(tǒng)不進(jìn)入死鎖狀態(tài)的動(dòng)態(tài)策略。
理解了死鎖的原因,尤其是產(chǎn)生死鎖的四個(gè)必要條件,就可以最大可能地避免、預(yù)防和解除死鎖。所以,在系統(tǒng)設(shè)計(jì)、進(jìn)程調(diào)度等方面注意如何讓這四個(gè)必要條件不成立,如何確定資源的合理分配算法,避免進(jìn)程永久占據(jù)系統(tǒng)資源。此外,也要防止進(jìn)程在處于等待狀態(tài)的情況下占用資源。因此,對(duì)資源的分配要給予合理的規(guī)劃。
死鎖避免和死鎖預(yù)防的區(qū)別:
死鎖預(yù)防是設(shè)法至少破壞產(chǎn)生死鎖的四個(gè)必要條件之一,嚴(yán)格的防止死鎖的出現(xiàn),而死鎖避免則不那么嚴(yán)格的限制產(chǎn)生死鎖的必要條件的存在,因?yàn)榧词顾梨i的必要條件存在,也不一定發(fā)生死鎖。死鎖避免是在系統(tǒng)運(yùn)行過(guò)程中注意避免死鎖的最終發(fā)生。
39、什么是線程池,如何使用?
創(chuàng)建線程要花費(fèi)昂貴的資源和時(shí)間,如果任務(wù)來(lái)了才創(chuàng)建線程那么響應(yīng)時(shí)間會(huì)變長(zhǎng),而且一個(gè)進(jìn)程能創(chuàng)建的線程數(shù)有限。為了避免這些問(wèn)題,在程序啟動(dòng)的時(shí)候就創(chuàng)建若干線程來(lái)響應(yīng)處理,它們被稱為線程池,里面的線程叫工作線程。從JDK1.5開始,Java API提供了Executor框架讓你可以創(chuàng)建不同的線程池。比如單線程池,每次處理一個(gè)任務(wù);數(shù)目固定的線程池或者是緩存線程池(一個(gè)適合很多生存期短的任務(wù)的程序的可擴(kuò)展線程池)。
40、Java中堆和棧有什么不同?
為什么把這個(gè)問(wèn)題歸類在多線程和并發(fā)面試題里?因?yàn)闂J且粔K和線程緊密相關(guān)的內(nèi)存區(qū)域。每個(gè)線程都有自己的棧內(nèi)存,用于存儲(chǔ)本地變量,方法參數(shù)和棧調(diào)用,一個(gè)線程中存儲(chǔ)的變量對(duì)其它線程是不可見的。而堆是所有線程共享的一片公用內(nèi)存區(qū)域。對(duì)象都在堆里創(chuàng)建,為了提升效率線程會(huì)從堆中弄一個(gè)緩存到自己的棧,如果多個(gè)線程使用該變量就可能引發(fā)問(wèn)題,這時(shí)volatile 變量就可以發(fā)揮作用了,它要求線程從主存中讀取變量的值。
41、有三個(gè)線程T1,T2,T3,怎么確保它們按順序執(zhí)行?
在多線程中有多種方法讓線程按特定順序執(zhí)行,你可以用線程類的join()方法在一個(gè)線程中啟動(dòng)另一個(gè)線程,另外一個(gè)線程完成該線程繼續(xù)執(zhí)行。為了確保三個(gè)線程的順序你應(yīng)該先啟動(dòng)最后一個(gè)(T3調(diào)用T2,T2調(diào)用T1),這樣T1就會(huì)先完成而T3最后完成。
線程間通信
我們知道線程是CPU調(diào)度的最小單位。在Android中主線程是不能夠做耗時(shí)操作的,子線程是不能夠更新UI的。而線程間通信的方式有很多,比如廣播,Eventbus,接口回掉,在Android中主要是使用handler。handler通過(guò)調(diào)用sendmessage方法,將保存消息的Message發(fā)送到Messagequeue中,而looper對(duì)象不斷的調(diào)用loop方法,從messageueue中取出message,交給handler處理,從而完成線程間通信。
線程池
Android中常見的線程池有四種,F(xiàn)ixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。
FixedThreadPool線程池是通過(guò)Executors的new FixedThreadPool方法來(lái)創(chuàng)建。它的特點(diǎn)是該線程池中的線程數(shù)量是固定的。即使線程處于閑置的狀態(tài),它們也不會(huì)被回收,除非線程池被關(guān)閉。當(dāng)所有的線程都處于活躍狀態(tài)的時(shí)候,新任務(wù)就處于隊(duì)列中等待線程來(lái)處理。注意,F(xiàn)ixedThreadPool只有核心線程,沒(méi)有非核心線程。
CachedThreadPool線程池是通過(guò)Executors的newCachedThreadPool進(jìn)行創(chuàng)建的。它是一種線程數(shù)目不固定的線程池,它沒(méi)有核心線程,只有非核心線程,當(dāng)線程池中的線程都處于活躍狀態(tài),就會(huì)創(chuàng)建新的線程來(lái)處理新的任務(wù)。否則就會(huì)利用閑置的線程來(lái)處理新的任務(wù)。線程池中的線程都有超時(shí)機(jī)制,這個(gè)超時(shí)機(jī)制時(shí)長(zhǎng)是60s,超過(guò)這個(gè)時(shí)間,閑置的線程就會(huì)被回收。這種線程池適合處理大量并且耗時(shí)較少的任務(wù)。這里得說(shuō)一下,CachedThreadPool的任務(wù)隊(duì)列,基本都是空的。
ScheduledThreadPool線程池是通過(guò)Executors的newScheduledThreadPool進(jìn)行創(chuàng)建的,它的核心線程是固定的,但是非核心線程數(shù)是不固定的,并且當(dāng)非核心線程一處于空閑狀態(tài),就立即被回收。這種線程適合執(zhí)行定時(shí)任務(wù)和具有固定周期的重復(fù)任務(wù)。
SingleThreadExecutor線程池是通過(guò)Executors的newSingleThreadExecutor方法來(lái)創(chuàng)建的,這類線程池中只有一個(gè)核心線程,也沒(méi)有非核心線程,這就確保了所有任務(wù)能夠在同一個(gè)線程并且按照順序來(lái)執(zhí)行,這樣就不需要考慮線程同步的問(wèn)題。