java面試突擊本由SnailClimb文章大部分內(nèi)容來源于本人開源項目_第1頁
java面試突擊本由SnailClimb文章大部分內(nèi)容來源于本人開源項目_第2頁
java面試突擊本由SnailClimb文章大部分內(nèi)容來源于本人開源項目_第3頁
java面試突擊本由SnailClimb文章大部分內(nèi)容來源于本人開源項目_第4頁
java面試突擊本由SnailClimb文章大部分內(nèi)容來源于本人開源項目_第5頁
已閱讀5頁,還剩74頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

本文檔由Sailmb整理,文章大部分內(nèi)容來源于本人的開源項目JavaGuide,你可以把這個文檔看做JavaGie的精簡版,適合面試前的突擊。內(nèi)容,歡迎關注:JvaGuide。需對應文章請附下面一段內(nèi)容:本文自JavaGuide,地址 /Snailclimb/JavaGuide,作者歷史更時說2019-2-第一不論是校招還是社招都避免不了各種面試、筆試,如何去準備這些東西就顯得格外重要。不論是筆試還是面試都是有章可循的,我這個“有章可循”說的意思只是說應對技術面試是可以提前準備。運籌帷幄之后,決勝千里之外!不打毫無準備的仗,我覺得大家可以先從下面幾個方面來準備面自我介紹。(你可千萬這樣介紹:“我叫某某,,來自哪里,學校是那個,自己愛干什么”,住:說點簡歷上沒有的,多說點自己哪里比別人強!)自己面試中可能涉及哪些知識點、那些知識點是重面試中哪些問題會被經(jīng)常問到、面試中自己改如何回答。(強烈不推薦背題,第一:通過背這種方式你能記住多少?能記住多久?第二:背題的方式的學習很難堅持下去!)自己的簡歷該如何寫“80%的o?er掌握在%的人手中”這句話也不是不無道理的。決定你面試能否成功的因素中實力固然占有很大一部分比例,但是如果你的心態(tài)或者說運氣不好的話,依然無法拿到滿意的oer。運氣暫且不談,就拿心態(tài)來說,千萬不要因為面試失敗而氣餒或者說懷疑自己的能力,面試失敗之后多總結一下失敗的原因,后面你就會發(fā)現(xiàn)自己會越來越強大。另外,大家要明確的很重要的幾點寫在簡歷上的東西一定要慎重,這可能是面試官大量提問的地大部分應屆生找工作的硬傷是沒有工作經(jīng)驗或?qū)嵙暯?jīng)將自己的項目經(jīng)歷完美的展示出來非常重筆主能力有限,如果有不對的地方或者和你想法不同的地方,敬請雅正、不舍賜—俗話說的好:“工欲善其事,必先利其器”。準備一份好的簡歷對于能不能找到一份好工作起到了至關重要的作用。為什么說簡歷很重要先從面試前來說假如你是網(wǎng)申,你的簡歷必然會經(jīng)過HR的篩選,一張簡歷HR可能也就花費10秒鐘看一下,然后HR關是Fal還是Pass。另外,就算你通過了篩選,后面的面試中,面試官也會根據(jù)你的簡歷來判斷你究竟是否值得他花費很多時間去面試。所以,簡歷就像是我們的一個門面一樣,它在很大程度上決定了你能否進入到下一輪的面試中。再從面試中來說我發(fā)現(xiàn)大家比較喜歡看面經(jīng),這點無可厚非,但是大部分面經(jīng)都沒告訴你很多問題都是在特定條件下才問的。舉個簡單的例子:一般情況下你的簡歷上注明你會的東西才會被問到(Java、數(shù)據(jù)結構、網(wǎng)絡、算法這些基礎是每個人必問的),比如寫了你會edis,那面試官就很大概率會問你s的一些問題。比如:s的常見數(shù)據(jù)類型及應用場景、s是單線程為什么還這么快、s和memcached的區(qū)別、es內(nèi)存淘汰機制等等。所以,首先,你要明確的一點是:你不會的東西就不要寫在簡歷上。另外,你要考慮你該如何才能讓你的亮點在簡歷中凸顯出來,比如:你在某某項目做了什么事情解決了什么問題(只要有項目就一定有要解決的問題)面試和工作是兩回事,聰明的人會把面試官往自己擅長的領域領,其他人則被面試官牽著鼻子走。雖說面試和工作是兩回事,但是你要想要獲得自己滿意的or,你自身的實力必須要強。這3大部的R都說我們不看重學歷(騙你的?。侨绻愕膶W校不出眾的話,很難在一堆簡歷中脫穎而出,除非你的簡歷上有特別的亮點,比如:某某大廠的實習經(jīng)歷、獲得了某某大賽的獎等等。大部分應屆生找工作的硬傷是沒有工作經(jīng)驗或?qū)嵙暯?jīng)歷,所以如果你是應屆生就不要錯過秋招和春招。一旦錯過,你后面就極大可能會社招,這個時候沒有工作經(jīng)驗的你可能就會各種碰壁,導致找不到一個好的工作寫在簡歷上的東西一定要慎重,這是面試官大量提問的地將自己的項目經(jīng)歷完美的展示出來非常重你必須知道的兩①STAR法則(SituationTaskActionResult):Situation:事情是在什么情況下發(fā)生;Task::你是如何明確你的任務的Action:針對這樣的情況分析,你采用了什么行動方Result:結果怎樣,在這樣的情況下你學習到了什簡而言之,SAR法則,就是一種講述自己故事的方式,或者說,是一個清晰、條理的作文模板。不管是什么,合理熟練運用此法則,可以輕松的對面試官描述事物的邏輯方式,表現(xiàn)出自己分析闡述問題的清晰性、條理性和邏輯性。下面這段內(nèi)容摘自百科,我覺得寫的非常不錯SAR法則,500強面試題回答時的技巧法則,備受面試者成功者和500強HR的推崇。由于這個法則被廣泛應用于面試問題的回答,盡管我們還在寫簡歷階段,但是,寫簡歷時能把面試的問題就想好,會使自己更加主動和自信,做到簡歷,面試關聯(lián)性,邏輯性強,不至于在一個月后去面試,卻把簡歷里的東西都忘掉了(更何況有些朋友會稍微夸大簡歷內(nèi)容)。在我們寫簡歷時,每個人都要寫上自己的工作經(jīng)歷,活動經(jīng)歷,想必每一個同學,都會起碼花上半天甚至更長的時間去搜尋腦海里所有有關的經(jīng)歷,爭取找出最好的東西寫在簡歷上。但是此時,我們要注意了,簡歷上的任何一個信息點都有可能成為日后面試時的重點提問對象,所以說,不能寫上讓自己感覺最牛的經(jīng)歷就完事了,要想到今后,在面試中,你所寫的經(jīng)歷萬一被面試官問到,你真的能回答得流利,順暢,且能通過這段經(jīng)歷,證明自己正是適合這個職位的人嗎?②FAB法則(FeatureAdvantageFeature:是什么Advantage:比別人好在哪些地方Bene?t:如果雇傭你,招聘方會得到什么好簡單來說,這個法則主要是讓你的面試官知道你的優(yōu)勢、招了你之后對公司有什么幫簡歷上有一兩個項目經(jīng)歷很正常,但是真正能把項目經(jīng)歷很好的展示給面試官的非常少。對于項目經(jīng)歷大家可以考慮從如下幾點來寫:簡歷上有一兩個項目經(jīng)歷很正常,但是真正能把項目經(jīng)歷很好的展示給面試官的非常少。對于項目經(jīng)歷大家可以考慮從如下幾點來寫:對項目整體設計的一個在這個項目中你負責了什么、做了什么、擔任了什么從這個項目中你學會了那些東西,使用到了那些了那些新技術的使另外項目描述中,最好可以體現(xiàn)自己的綜合素質(zhì),比如你是如何協(xié)調(diào)項目組成員協(xié)同開發(fā)的或者在遇到某一個棘手的問題的時候你是如何解決的又或者說你在這個項目用了什么技術實現(xiàn)了什么功能比如:es速度和并發(fā)量、使用消息隊列削峰和降流等等。先問一下你自己會什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技術,所以他在篩選簡歷的時候可能就盯著你專業(yè)技能的來看。對于公司有要求而你不會的技能,你可以花幾天時間學 下,然后在簡歷上可以寫上自己了解這個技能。比如你可以這樣寫:Dubbo:精通Spring:精通SOA分布式開發(fā):掌SpringCloud:一 上開源的程序員簡歷模板。包括PHP程序員簡歷模板、iOS程序員簡歷模板、Android程序員簡歷模板以及通用程序員簡歷模板。 如果想學如何用Markdown寫簡歷寫一份高質(zhì)量簡歷,請看這里: 其他的一些小盡量避免表述,少一點語義模糊的形容詞,盡量要簡潔明了,邏輯結構清晰注意排版(不需要花花的),盡量使用Markdown語法如果自己有博客或者個人技術棧點的話,寫上去會為你加分很如果自己 比較活躍的話,寫上去也會為你加分很多注意簡歷真實性,一定不要寫自己不會的東西,或者帶有性的內(nèi)項目經(jīng)歷建議以時間倒序排序,另外項目經(jīng)歷不在于多,而在于有亮如果內(nèi)容過多的話,不需要非把內(nèi)容壓縮到一頁,保持排版干凈整潔就可以了簡歷最后最好能加上:“感謝您花時間閱讀簡歷,期待能有機會和您共事。”這句話,顯的你會很有禮貌Java基礎重載:發(fā)生在同一個類中,方法名必須相同,參數(shù)類型不同、個數(shù)不同、順序不同,方法返回值和修飾符可以重寫:發(fā)生在父子類中,方法名、參數(shù)列表必須相同,返回值范圍小于等于父類,拋出的異常范圍小于等于父類,修飾符范圍大于等于父類;如果父類方法修飾符為private則子類就不能重寫該方法。String和StringBu?er、StringBuilder的區(qū)別是什么?String為什可變簡單的來說:String類中使用?nal關鍵字字符數(shù)組保存字符串,privatefinalcharvalue[],所以String對象是不可變的。而StringBuilder與StringBu?er都繼承自 StringBuilder類,在 中也是使用字符數(shù)組保存字符串char[]value但是沒有用?nal關鍵字修飾,所以這兩種對象都是可變的。StringBuilder與StringBu?er的構造方法都是調(diào)用父類構造方法也就是 StringBuilder實現(xiàn)的,大家可以自 StringBuilderimplementsAppendable,{char[]value;intcount;StringBuilder()}StringBuilder(int{value=new}線程安全Strig中的對象是不可變的,也就可以理解為常量,線程安全。 StrigBiler是StrigBuiler與StrigB?r的公共父類,定義了一些字符串的基本操作,如exandCapacity、apedinsertidexOf等公共方法。StringBu?r對方法加了同步鎖或者對調(diào)用的方法加了同步鎖,所以是線程安全的。StrinBidr并沒有對方法進行加同步鎖,所以是非線程安全的。性每次對String類型進行改變的時候,都會生成一個新的String對象,然后將指針指向新的String對象。StringBu?er每次都會對StringBu?er對象本身進行操作,而不是生成新的對象并改變對象。相同情況下使用StirngBuilder相比使用StringBu?er僅能獲得10%~15%左右的性能提升,但卻要冒多線程不安全的風險。對于三者使用的總結操作少量的數(shù)據(jù)=單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù)=多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù)=2.1.4==:它的作用是判斷兩個對象的地址是不是相等。即,判斷兩個對象是不是同一個對象。(基本數(shù)據(jù)類型==比較的是值,數(shù)據(jù)類型==比較的是內(nèi)存地址)equals():它的作用也是判斷兩個對象是否相等。但它一般有兩種使用情情況1:類沒有覆蓋equals()方法。則通過equals()比較該類的兩個對象時,等價于通過“==”比較這兩個對象。情況2:類覆蓋了equals()方法。一般,我們都覆蓋equals()方法來兩個對象的內(nèi)容相等;若它們的內(nèi)容相等,則返回true即,認為這兩個對象相等)。publicpublicclasstest1publicstaticvoidmain(String[]StringanewString("ab"a為一個引Stringb=newString("ab");//b為另一個 Stringaa="ab";//放在常量池中Stringbb"ab"從常量池中查if(aa==bb)//if(a==b)//false,非同一對象if(a.equals(b))//trueif(42==42.0){//true}}說明String中的equals方法是被重寫過的,因為object的equals方法是比較的對象的內(nèi)存地址,而Stringequals方法比較的是對象的值當創(chuàng)建String類型的對象時,虛擬機會在常量池中查找有沒有已經(jīng)存在的值和要創(chuàng)建的值相同的對象,如果有就把它賦給當前。如果沒有就在常量池中重新創(chuàng)建一個String對象。關于?nal?nal關鍵字主要用在三個地方:變量、方法、類對于一個?nl變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改;如果是類型的變量,則在對其初始化之后便不能再讓其指向另一個對象。當用?nal修飾一個類時,表明這個類不能被繼承。?nal類中的所有成員方法都會被隱式地指定為?nal方法使用nl方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率。在早期的Java實現(xiàn)版本中,會將?nl方法轉為內(nèi)嵌調(diào)用。但是如果方法過于龐大,可能看不到內(nèi)嵌調(diào)用帶來的任何性能提升(現(xiàn)在的Java版本已經(jīng)不需要使用nl方法進行這些優(yōu)化了)。類中所有的ivate方法都隱式地指定為?al。Object類是一個特殊的類,是所有類的父類。它主要提供了以下11個方法publicfinalnativeClass<?>getClass()//native方法,用于返回當前運行時對象的Class對象,使用了publicnativeinthashCode/native方法,用于返回對象的哈希碼,主要使用在哈希表中,比如JDK中的publicbooleanequals(Objectobj)//用于比較2個對象的內(nèi)存地址是否相等,String類對該方法進行了重寫用protectednativeObjectclone()throwsCloneNotSupportedException//naitive方法,用于創(chuàng)建并返回當前對象的一份拷貝。一般情況下,對于任何對象x,表達式x.clone()!=x為true,x.clone().getClassx.getClass()為true。Object本身沒有實現(xiàn)Cloneable接口,所以不重寫clonepublicStringtoString()//返回類的名字@實例的哈希碼的16進制的字符串。建議Object所有的子類都重寫這個publicfinalnativevoidnotify()//native方法,并且不能重寫。喚醒一個在此對象監(jiān)視器上等待的線程(監(jiān) publicfinalnativevoidnotifyAll()//native方法,并且不能重寫。跟notify一樣,唯一的區(qū)別就是會喚能重寫。暫停線程的執(zhí)行。注意:sleep方法沒有釋放鎖,而wait方法釋放了鎖。timeout是等待時間。publicfinalvoidwait(longtimeoutintnanosthrowsInterruptedException//多了nanos參數(shù),這個參數(shù)表示額外時間(以毫微秒為單位,范圍是0-999999)。所以超時的時間還需要加上nanos毫秒。publicpublicfinalvoidwait()throwsInterruptedException//跟之前的2個wait方法一樣,只不過該方法一直protectedvoidfinalize()throwsThrowable{}//實例 回收器回收的時候觸發(fā)的操JavaJava異常類層次結構在Java中,所有的異常都有一個共同的祖先java.lang包中的Throwable類。Throwable:有兩個重要的子類Exception(異常)和Error(錯誤),二者都是Java異常處理的重要子類,各自都包含大量子Error(錯誤):是程序無法處理的錯誤,表示運行應用程序中較嚴重問題。大多數(shù)錯誤與代碼編寫者執(zhí)行的操作關,而表示代碼運行時JVM(Java虛擬機)出現(xiàn)的問題。例如,Java虛擬機運行錯誤(VirtualMachineError),當JVM不再有繼續(xù)執(zhí)行操作所需的內(nèi)存資源時,將出現(xiàn)OutOfMemoryError。這些異常發(fā)生時,Java虛擬機(JVM)一處理能力之外,而且絕大多數(shù)是程序運行時不允許出現(xiàn)的狀況。對于設計合理的應用程序來說,即使確實發(fā)生了錯誤,本質(zhì)上也不應該試圖去處理它所引起的異常狀況。在Java中,錯誤通過Error的子類描述。Eption(異常):是程序本身可以處理的異常。Eceon類有一個重要的子類RuntimeEcption。RntimeEception異常由Java虛擬機拋出。NullointrEption(要的變量沒有任何對象時,拋出該異常)、AritheticEeption(算術運算異常,一個整數(shù)除以0時,拋出該異常)和AraIndOutOfBoundEption(下標越界異常)。注意:異常和錯誤的區(qū)別:異常能被程序本身可以處理,錯誤是無法處Throwable類常用方publicstringgetMessage():返回異常發(fā)生時的詳細信息publicstringtoString():返回異常發(fā)生時的簡要描述publicstringgLolizedMessag):返回異常對象的本地化信息。使用ThwalegetMessage()返回的結果相同publicvoidprintStck:在控制臺上打印Thwable對象封裝的異常信息異常處理總 塊:用于捕獲異常。其后可接零個或多個catch塊,如果沒有catch塊,則必須跟一個?nally塊catch塊:用于處理try捕獲到的異常y塊:無論是否捕獲或處理異常,塊里的語句都會被執(zhí)行。當在y語句塊將在方法返回之前被執(zhí)行。在以下4種特殊情況下,?nally塊不會被執(zhí)行在?nally語句塊中發(fā)生了異面的代碼中用了System.exit()退出程序程序所在的線程關閉CPU方法1:通過Strings=input.nextLine();方法2:通過Strings=input.readLine();接口的方法默認是public,所有方法在接口中不能有實現(xiàn)Java8開始接口方法可以有默認實現(xiàn)),抽象類可以接口中的實例變量默認是?nal類型的,而抽象類中則不一個類可以實現(xiàn)多個接口,但最多只能實現(xiàn)一個抽一個類實現(xiàn)接口的話要實現(xiàn)接口的所有方法,而抽象類不接口不能用new實例化,但可以,但是必須一個實現(xiàn)該接口的對象從設計層面來說,抽象是對類的抽備注:在JDK8中,接口也可以定義靜態(tài)方法,可以直接用接口名調(diào)用。實現(xiàn)類是不可以調(diào)用的。如果同時實現(xiàn)兩個接口,接口中定義了一樣的默認方法,必須重寫,不然會報錯。(詳見 Java集合是否保證線程安全:ArrayList和LinkedList都是不同步的,也就是不保證線程安底層數(shù)據(jù)結構:Arraylist底層使用的是Object數(shù)組;LinkedList底層使用的是雙向鏈表數(shù)據(jù)結構(JDK1.6之前為循環(huán)鏈表,JDK1.7取消了循環(huán)。注意雙向鏈表和雙向循環(huán)鏈表的區(qū)別:);詳細可閱讀JDK1.7-LinkedList和刪除是否受元素位置的影響:①ArrayList采用數(shù)組,所以和刪除元素的時間復雜度受元素位置的影響。比如:執(zhí)行add(Ee方法的時候,ArrayList會默認在將指定的元素追加到此列表的末尾,這種情況時間復雜度就是O(1)。但是如果要在指定位置i和刪除元素的話(add(intindex,Eelement))時間復雜度就為O(n-i)。因為在進行上述操作的時候集合中第ii個元后的(n-i)個元素都要執(zhí)行向后位/向前移一位的操作。②LinkedList采用鏈表,所以,刪除元素時間復雜度不受元素位置的影響,都是近似O(1)而數(shù)組為近似O(n)。是否支持快速隨機:LinkedList不支持高效的隨機元素,而ArrayList支持??焖匐S機就是通過元素的序號快速獲取元素對象(對應于get(intindex)方法)。內(nèi)存空間占用:ArrayList的空間浪費主要體現(xiàn)在在list列表的結尾會預留一定的容量空間,而LinkedList的空據(jù))。-6.發(fā)補充內(nèi)容:RandomAccess接口publicpublicinterfaceRandomAccess}查看源碼我們發(fā)現(xiàn)實際上RandomAccess接口中什么都沒有定義。所以,在我看來RandomAccess接口不過是一個標識罷了。標識什么?標識實現(xiàn)這個接口的類具有隨機功能。在binarySearch()方法中,它要判斷傳入的 是否RamdomAccess的實例,如果是,調(diào)indexedBinarySearch()方法,如果不是,那么調(diào)用iteratorBinarySearch()方publicpublicstaticintbinarySearch(List<?extendsComparable<?superT>>list,Tkey)returnCollections.indexedBinarySearch(list,key);returnCollections.iteratorBinarySearch(list,}ArrayList實現(xiàn)了RandomAccess接口,而LinkedList沒有實現(xiàn)。為什么呢?我覺得還是和底層數(shù)據(jù)結構有關!ArrayList底層是數(shù)組,而LinkedList底層是鏈表。數(shù)組天然支持隨機,時間復雜度為O(1),所以稱為快速隨機。鏈表需要遍歷到特定位置才能特定位置的元素,時間復雜度為O(n),所以不支持快速隨機。,ArrayList實現(xiàn)了RandomAccess接口,就表明了他具有快速隨機功能。RandomAccess接口只是標識,并不是說ArrayList實現(xiàn)RandomAccess接口才具有快速隨機功能的!下面再總結一下list的遍歷方式選擇實現(xiàn)了RandomAccess接口的list,優(yōu)先選擇普通for循環(huán),其次未實現(xiàn)mst,r(r實現(xiàn)的),大ze的數(shù)據(jù),千萬不要使用普通r補充:數(shù)據(jù)結構基礎之雙向雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數(shù)據(jù)結點中都有兩個指針,分別指向直接后繼和直接前驅(qū)。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地它的前驅(qū)結點和后繼結點。一般我們都構造雙向循環(huán)鏈表,如下圖所示,同時下圖也是Linst底層使用的是雙向循環(huán)鏈表數(shù)據(jù)結構。ArrayList與Vectorr類的所有方法都是同步的??梢杂蓛蓚€線程安全地一個ector對象、但是一個線程r在同步操作上耗費大量的時間。Arraylist不是同步的,所以在不需要保證線程安全時時建議使用ArraylistJDK1.8之(n-1)&JDK1.8之前HashMap底層是數(shù)組和鏈表結合在一起使用也就是鏈表散列。HashMap通過key的hashCode經(jīng)過擾動函數(shù)處理過后得到hash值,然后通過 判斷當前元素存放的位置(這里的n指的是數(shù)組的長度),如果當前位置存在元素的話,就判斷該元素與要存入的元素的hash值以及key是否(n-1)&話,直接覆蓋,不相同就通過拉鏈法解決所謂擾動函數(shù)指的就是HashMap的hash方法。使用hash方法也就是擾動函數(shù)是為了防止一些實現(xiàn)比較hashCode()方法換句話說使用擾動函數(shù)之后可以減少碰JDK1.8HashMap的hash方法源碼JDK1.8hash方法比于JDK1.7hash方法更加簡化,但是原理不staticstaticfinalinthash(Object{int//key.hashCode():返回散列值也就是^//>>>:無符號右移,忽略符號位,空位都以0return(key==null)?0:(h=key.hashCode())^(h>>>}對比一下JDK1.7的HashMap的hash方法源碼staticstaticinthash(inth)//ThisfunctionensuresthathashCodesthatdifferonly//constantmultiplesateachbitpositionhavea//numberofcollisions y8atdefaultloadh^=(h>>>20)^(h>>>returnh^(h>>>7)^(h>>>}相比于JDK1.8hashJDK1.7hash方法的性能會稍差一點點,因為畢竟擾動了4次所謂“拉鏈法”就是:將鏈表和數(shù)組相結合。也就是說創(chuàng)建一個鏈表數(shù)組,數(shù)組中每一格就是一個鏈表。若遇到哈,則將的值加到鏈表中即可JDK1.8之相比于之前的版本,JDK1.8之后在解決哈希時有了較大的變化,當鏈表長度大于閾值(默認為8)時,將鏈表轉TreeMap、TreeSet以及JDK1.8之后的HashMap底層都用到了樹。樹就是為了解決二叉查找樹的缺陷,因為二叉查找樹在某些情況下會成一個線性結構。推薦閱讀《Java8系列之重新認識HashMap》: HashMap和Hashtable線程是否安全:HashMap是非線程安全的,HashTable是線程安全的;HashTable的方法基本都經(jīng)過修飾。(如果你要保證線程安全的話就使用ConcurrentHashMap吧?。?;效率:因為線程安全的問題,HashMap要比HashTable效率高一點。另外,HashTable基本被淘汰,不要在對Nullkey和Nullvalue的支持:HashMap中,null可以作為鍵,這樣的鍵只有一個,可以有一個或多個鍵所對應的值為null。。但是在HashTable中put進的鍵值只要有一個null,直接拋出NullPointerException。初始容量大小和每次擴充容量大小的不同:①創(chuàng)建時如果不指定容量初始值,Hashtable默認的初始大小11,之后每次擴充,容量變?yōu)樵瓉淼?n1HsMp默認的初始化大小為16。之后每次擴充,容量變?yōu)樵瓉淼?倍。②創(chuàng)建時如果給定了容量初始值,那么Hastable會直接使用你給定的大小,而HashMp為2的冪次方大?。℉asMp中的tableSizeFor()方法保證,下面給出了源代碼)。也就是說HsMp總是使用2的冪作為哈希表的大小,后面會介紹到為什么是2的冪次方。底層數(shù)據(jù)結構:JDK1.8以后的HashMap在解決哈希時有了較大的變化,當鏈表長度大于閾值(默認8)時,將鏈表轉化為樹,以減少搜索時間。Hashtable沒有這樣的機制HasMap中帶有初始容量的構造函publicpublicHashMap(intinitialCapacity,float{if(initialCapacity<thrownewIllegalArgumentException("Illegalinitialcapacity:"if(initialCapacity> initialCapacity if(loadFactor<=0||thrownewIllegalArgumentException("Illegalloadfactor:"this.loadFactor=}publicHashMap(int{this(initialCapacity,}下面這個方法保證了HashMap總是使用2的冪作為哈希表的大*ReturnsapoweroftwosizeforthestaticfinalinttableSizeFor(int{intn=cap-1;n|=n>>>1;n|=n>>>2;n|=n>>>4;n|=n>>>n|=n>>>return(n<0)?1:(n UM_CAPACITY) UM_CAPACITY:n+}HashMap的長度為什么是2(n-1)&為了能讓HashMp存取高效,盡量較少碰撞,也就是要盡量把數(shù)據(jù)分配均勻。我們上面也講到了過了,Hash值的范圍值- 到 47,前后加起來大概40億的空間,只要哈希函數(shù)得比較均勻松散,一般應用是很難出現(xiàn)碰撞的。但問題是一個40億長度的數(shù)組,內(nèi)存是放不下的。所以這個散列值是不能直接拿來用的。用之前還要先做對數(shù)組的長度取模運算,得到的余數(shù)才能用來要存放的位置也就是對應的數(shù)組下標。這個數(shù)組下標的計算方法是“ ”。(n代表數(shù)組長度)。這也就解釋了HashM(n-1)&這個算法應該如何設計我們首先可能會想到采用%取余的操作來實現(xiàn)。但是,重點來了:“取余(%)操作中如果除數(shù)是2的冪次則等價于與其除數(shù)減一的與(&)操作(也就是說hash%length==hash&(length-1)的前提是length是2的n次方;)?!辈⑶也捎枚M制位操作&,相對于%能夠提高運算效率,這就解釋了HahMap的長度為什么是2的冪次方。HashMap在多線程下,進行put操作會導致HashMp死循環(huán),原因在于HsMp的擴容sz()方法。由于擴容是新建一個數(shù)組,原數(shù)據(jù)到數(shù)組。由于數(shù)組下標掛有鏈表,所以需要鏈表,但是多線程操作有可能導致環(huán)形鏈表。復制鏈表過程如下:以下模擬2個線程同時擴容。假設,當前HashMap的空間為2(臨界值為1),hashcode分別為0和1,在散列0處有元素AB,這時候要添加元素C,C經(jīng)過hash運算,得到散列地址為1,這時候由于超過了臨界值,空間不夠,需要調(diào)用resize方法進行擴容,那么在多線程條件下,會出現(xiàn)條件競爭,模擬過程如下:線程一:到當前的HashMap情況,在準備擴容時,線程二介線程二:HashMap,進行擴線程一:繼續(xù)執(zhí)這個過程為,先將A到新的hash表中,然后接著B到鏈頭(A的前邊:B.next=A),本來B.next=null,到此也就結束了(跟線程二一樣的過程),但是,由于線程二擴容的原因,將B.next=A,所以,這里繼續(xù)A,讓A.next=B,由此,環(huán)形鏈表出現(xiàn):B.next=A;A.next=B注意:jdk1.8已經(jīng)解決了死循環(huán)的問題HashSet和HashMap如果你看過HashSet源碼的話就應該知道:HashSet底層就是基于HashMap實現(xiàn)的。(HashSet的源碼非常非常少,因為除了clone()方法、writeObject()方法、readObject()方法是HashSet自己不得不實現(xiàn)之外,其他方法都是直接調(diào)用HashMap中的方法。)ConcurrentHashMap和HashtableConcurrentHashMap和Hashtable的區(qū)別主要體現(xiàn)在實現(xiàn)線程安全的方式上不底層數(shù)據(jù)結構:JDK1.7的ConcurrentHashMap底層采用分段的數(shù)組+鏈表實現(xiàn),JDK1.8采用的數(shù)據(jù)結構跟HashMap1.8的結構一樣,數(shù)組+鏈表/二叉樹。Hashtable和JDK1.8之前的HashMap的底層數(shù)據(jù)結構類似都是采用數(shù)組+鏈表的形式,數(shù)組是HashMap的主體,鏈表則是主要為了解決哈希而存在的;實現(xiàn)線程安全的方式(重要):①在JDK1.7的時候,ConcurentHahMp(分段鎖)對整個桶數(shù)組進行了分割分段(Segment),每一把鎖只鎖容器其中一部分數(shù)據(jù),多線程容器里不同數(shù)據(jù)段的數(shù)據(jù),就不會存在鎖競爭,提高并發(fā)率。到了JDK1.8的時候已經(jīng)摒棄了Segent的概念,而是直接用Node數(shù)組+鏈表+樹的數(shù)據(jù)結構來實現(xiàn),并發(fā)控制使用nhonized和CAS來操作。(JDK1.6以后對nhonized多優(yōu)化)整個看起來就像是優(yōu)化過且線程安全的HashMap,雖然在JDK1.8中還能看到Sgment的數(shù)據(jù)結構,但是已經(jīng)簡化了屬性,只是為了兼容舊版本;②Hashtble(同一把鎖):使用sychoized來保證線程安全,效率非常低下。當一個線程同步方法時,其他線程也同步方法,可能會進入阻塞或輪詢狀態(tài),如使用put添加元素,另一個線程不能使用put添加元素,也不能使用get,競爭會越來越激烈效率越低。兩者的對比 JDK1.7的JDK1.8的ConcurrentHashMap(TreeBin:二叉樹節(jié)點Node:鏈表節(jié)點JDK1.7(上面有示意圖首先將數(shù)據(jù)分為一段一段的,然后給每一段數(shù)據(jù)配一把鎖,當一個線程占用鎖其中一個段數(shù)據(jù)時,其他段的ConcurrentHashMap是由Segment數(shù)組結構和HashEntry數(shù)組結構組成Segment實現(xiàn)了ReentrantLock,所以Segment是一種可重入鎖,扮演鎖的角色。HashEntry用于鍵值對數(shù)staticstaticclassSegment<K,V>extendsReentrantLockimplementsSerializable}一個ConcurrntHashMap里包含一個Sgmnt數(shù)組。Semnt的結構和HasMap類似,是一種數(shù)組和鏈表結構,一個Segmet包含一個HashEntry數(shù)組,每個Hry是一個鏈表結構的元素,每個Smt守護著一個HashEntry數(shù)組里的元素,當對HashEntry數(shù)組的數(shù)據(jù)進行修改時,必須首先獲得對應的Semnt的鎖。JDK1.8(上面有示意圖ConcurrentHashMap取消了Segment分段鎖,采用CAS和synchronized來保證并發(fā)安全。數(shù)據(jù)結構跟的結構類似,數(shù)組+鏈表/二叉樹synchronized只鎖定當前鏈表或二叉樹的首節(jié)點,這樣只要hash不,就不會產(chǎn)生并發(fā),效率又提升N倍Arraylist:Object數(shù)Vector:Object數(shù)LinkedList向鏈表JDK1.6之前為循環(huán)鏈表,JDK1.7取消了循環(huán)詳細可閱讀JDK1.7-LinkedList循環(huán)鏈表優(yōu)HashSet(無序,唯一):基于HashMap實現(xiàn)的,底層采用HashMap來保存LinkedHashSet:LinkedHashSet繼承與HashSet,并且其是通過LinkedHashMap來實現(xiàn)的。有點類似于我們之前說的LinkedHashMap其是基于Hashmap實現(xiàn)一樣,不過還是有一點點區(qū)別的。TreeSet(有序,唯一):樹(自平衡的排序二叉樹。)HashMap:JDK1.8之前HsMp由數(shù)組+鏈表組成的,數(shù)組是HashMp存在的(“拉鏈法”解決).JDK1.8以后在解決哈希時有了較大的變化,當鏈表長度大于閾值(默認為8)時,將鏈表轉化為樹,以減少搜索時間LindHahM:LinedHashMap繼承自HashMap,所以它的底層仍然是基于拉鏈式散列結構即由數(shù)組和鏈表或樹組成。另外,LinedHashMap在上面結構的基礎上,增加了一條雙向鏈表,使得上面的結構可以保持鍵值對的順序。同時通過對鏈表進行相應的操作,實現(xiàn)了順序相關邏輯。詳細可以查看:《LinkedHashMap源碼詳細分析(JDK1.8)HashTable:數(shù)組+鏈表組成的,數(shù)組是HashMap的主體,鏈表則是主要為了解決哈希而存在TreeMap:樹(自平衡的排序二叉樹Java多線關于Java多線面試的時候,問的比較多的就是①悲觀鎖和樂觀鎖(具體可以看這篇文章:面試必備之樂觀鎖與悲觀鎖)、②shonized和loc區(qū)別以及voltile和shonized的區(qū)別,③可重入鎖與非可重入鎖的區(qū)別、④多線程是解決什么問題的、⑤線程池解決什么問題、⑥線程池的原理、⑦線程池使用時的注意事項、⑧QS原理、⑨ReentLoc源碼,設計原理,整體過程等等問題。際使用Java多線程的經(jīng)歷的話,會為你加分不少哦!synchronized5說一說自己對于synchronizedsynchonzed關鍵字解決的是多個線程之間資源的同步性,synchoized鍵可以證被修飾方法者代碼塊在任意時刻只能有一個線程執(zhí)行。另外,在Java早期版本中,synchonzed屬于重量級鎖,效率低下,因為監(jiān)視器鎖(montor)是依賴于底層的操作系統(tǒng)的MutxLock來實現(xiàn)的,Java的線程是到操作系統(tǒng)的原生線程之上的。如果要掛起或者喚醒一個線程,都需要操作系統(tǒng)幫忙完成,而操作系統(tǒng)實現(xiàn)線程之間的切換時需要從用戶態(tài)轉換到內(nèi)核態(tài),這個狀態(tài)之間的轉換需要相對比較長的時間,時間成本相對較高,這也是為什么早期的synchoized效率低的原因。慶幸的是在Java6之后Java對從JVM層面對synchoized較大優(yōu)化,所以現(xiàn)在的synchoized鎖效率也優(yōu)化得很不錯了。JDK1.6對鎖的實現(xiàn)引入了大量的優(yōu)化,如自旋鎖、適應性自旋鎖、鎖消除、鎖粗化、偏向鎖、輕量級鎖等技術來減少鎖操作的開銷。說說自己是怎么使用synchronizedsynchronized關鍵字最主要的三種使用方修飾實例方法,作用于當前對象實例加鎖,進入同步代碼前要獲得當前對象實例修飾靜態(tài)方法,作用于當前類對象加鎖,進入同步代碼前要獲得當前類對象的鎖。也就是給當前類加鎖,會作用于類的所有對象實例,因為靜態(tài)成員不屬于任何一個實例對象,是類成員(static表明這是該類的一個靜態(tài)資源,不管nw了多少個對象,只有一份,所以對該類的所有對象都加了鎖)。所以如果一個線程A調(diào)用一個實例對象的非靜態(tài)synchonzed方法,而線程B需要調(diào)用這個實例對象所屬類的靜態(tài)synchoized方法,是允許的,不會發(fā)生互斥現(xiàn)象,因為靜態(tài)shonized方法占用的鎖是當前類的鎖,而非靜態(tài)nhonized方法占用的鎖是當前實例對象鎖。修飾代碼塊,指定加鎖對象,對給定對象加鎖,進入同步代碼庫前要獲得給定對象的鎖。和d方法一樣,syncroize(tis)代碼塊也是鎖定當前對象的。synchroizd關鍵字加到static靜態(tài)方法和synchroized(class)代碼塊上都是是給Cass類上鎖。這里再提一下:synchroizd關鍵字加到非sttic靜態(tài)方法上是給對象實例上鎖。另外需要注意的是:盡量不要使用synchrd(Stringa)因為JVM中,字符串常量池具有緩沖功能!下面我已一個常見的面試題為例講解一下synchronized關鍵字的具體使用面試中面試官經(jīng)常會說:“單例模式了解嗎?來給我手寫一下!給我解釋一下雙重檢驗鎖方式實現(xiàn)單例模式的原理唄!”雙重校驗鎖實現(xiàn)對象單例(線程安全publicpublicclassSingletonprivateSingleton()}publicstaticSingletongetUniqueInstance()ifif(uniqueInstance==null)synchronized{if(uniqueInstance=={uniqueInstance=new}}}return}另外,需要注意uniqueInstance采用volatile關鍵字修飾也是很有必uniqueInstancevolatile關鍵字修飾也是很有必要的uniqueInstancenewSingleton這段代碼其實是分為uniqueInstance初始化將uniqueInstance指向分配的內(nèi)存地但是由于JVM具有指令重排的特性,執(zhí)行順序有可能變成1->3->2。指令重排在單線程環(huán)境下不會出先問題,但是在多線程環(huán)境下會導致一個線程獲得還沒有初始化的實例。例如,線程T1執(zhí)行了1和3,此時T2調(diào)用getUniqueInstance()后發(fā)現(xiàn)uniqueInstance不為空,因此返回uniqueInstance,但此時uniqueInstance還未被使用volatile可以JVM的指令重排,保證在多線程環(huán)境下也能正常運行講一下synchronizedsynchronized關鍵字底層原理屬于JVM層面①synchronized同步語句塊的情publicclasspublicclass{publicvoidmethod(){synchronized(this)System.out.println("synchronized代碼塊}}}通過JDK自帶的javap命令查看SynchronizedDemo類的相關字節(jié)碼信息:首先切換到類的對應 命令生成編譯后的.class文件,然后執(zhí)行javap-c-s-v-l。從上面我們可以看出nhonized同步語句塊的實現(xiàn)使用的是monitoenter和monitot指令,其中monitoentermonitoxit指令則指明同步代碼塊的結束位置。當執(zhí)行monitoer指令時,線程試圖獲取鎖也就是獲取montor(montr對象存在于每個Java對象的對象頭中,synchonzed鎖便是通過這種方式獲取鎖的,也是為什么Java中任意對象可以作為鎖的原因)的持.當計數(shù)器為0則可以成功獲取,獲取后將鎖計數(shù)器設為1也就是加1。相應的在執(zhí)行monitoxit指令后,將鎖計數(shù)器設為0,表明鎖被釋放。如果獲取對象鎖失敗,那當前線程就要阻塞等待,直到鎖被另外一個線程釋放為止。②synchronized修飾方法的的情publicpublicclass{publicsynchronizedvoid{System.out.println("synchronized方法}}synchronized修飾的方法并沒有monitorenter指令和monitorexit指令,取得代之的確實是ACC_SYNCHRONIZED標識,該標識指明了該方法是一個同步方法,JVM通過該ACC_SYNCHRONIZED標志來JDK1.6之后的synchronized關鍵字底層做了哪些優(yōu)化,可以詳細介紹一下這些優(yōu)JDK1.6對鎖的實現(xiàn)引入了大量的優(yōu)化,如偏向鎖、輕量級鎖、自旋鎖、適應性自旋鎖、鎖消除、鎖粗化等技術來減鎖主要存在四種狀態(tài),依次是:無鎖狀態(tài)、偏向鎖狀態(tài)、輕量級鎖狀態(tài)、重量級鎖狀態(tài),他們會隨著競爭的激烈而逐漸升級。注意鎖可以升級不可降級,這種策略是為了提高獲得鎖和釋放鎖的效率。關于這幾種優(yōu)化的詳細信息可以查看:synchronized關鍵字使用、底層原理、JDK1.6之后的底層優(yōu)化以及ReenTrantLock的對談談synchronized和ReenTrantLock①兩者都是可重入兩者都是可重入鎖?!翱芍厝腈i”概念是:自己可以再次獲取自己的鎖。比如一個線程獲得了某個對象的鎖,此時這個對象鎖還沒有釋放,當其再次想要獲取這個對象的鎖的時候還是可以獲取的,如果不可鎖重入的話,就會造成死鎖。同一個線程每次獲取鎖,鎖的計數(shù)器都自增1,所以要等到鎖的計數(shù)器下降為0時才能釋放鎖。②synchronized依賴于JVM而ReenTrantLock依賴于synchronized是依賴于JVM實現(xiàn)的,前面我們也講到了虛擬機團隊在JDK1.6為synchronized關鍵字進行了很多優(yōu)化,但是這些優(yōu)化都是在虛擬機層面實現(xiàn)的,并沒有直接給我們。ReenTrantLock是JDK層面實現(xiàn)的(也就是API層面,需要lock()和unlock方法配合try/?nally語句塊來完成),所以我們可以通過查看它的源代碼,來看③ReenTrantLock比synchronized增加了一些高級功相比synchronized,ReenTrantLock增加了一些高級功能。主要來說主要有三點:①等待可中斷;②可實現(xiàn)公平鎖③可實現(xiàn)選擇性通知(鎖可以綁定多個條件RenLock提供了一種能夠中斷等待鎖的線程的機制,通過lock.ockInterruptib()RenLock可以指定是公平鎖還是非公平鎖。而synhonized只能是非公平鎖。所謂的公平鎖就是先等待的線程先獲得鎖。ReentLock默認情況是非公平的,可以通過ReentLock類的ReentrantLck(booleanfair)構造方法來制定是否是公平的。synchonzed關鍵字與wt()和nify/otifyAll()方法相結合可以實現(xiàn)等待/通知機制,ReetntLock類當然也可以實現(xiàn),但是需要借助于Condon接口與nwConitio)方法。Condon是JDK1.5Lock對象中可以創(chuàng)建多個Codon實例(即對象監(jiān)視器),線程對象可以在指定的Condition中,從而可以有選擇性的進行線程通知,在調(diào)度線程上更加靈活。在使用notifnotifAll()方法進行通知時,被通知的線程是由JVM選擇的,用ReenttLock類結合Condition實例可以實現(xiàn)“選擇性通知”,這個功能非常重要,而且是Condon接口默認提供的。而synchonzed關鍵字就相當于整個Lock對象中只有一個Condon實例,所有的線程都在它一個身上。如果執(zhí)行notifyAll()方法的話就會通知所有處于等待狀態(tài)的線程這樣會造成很大的效率問題,而Conition實例的signa()方法只會喚醒在該Codon實例中的所有等待線程。如果你想使用上述功能,那么選擇ReenTrantLock是一個不錯的選④性能已不是選擇標講一下Java內(nèi)存模在JDK1.2之前,Java的內(nèi)存模型實現(xiàn)總是從主存(即共享內(nèi)存)變量,是不需要進行特別的注意的。而在當前的Java內(nèi)存模型下,線程可以把變量保存本地內(nèi)存(比如機器的寄存器)中,而不是直接在主存中進行讀寫。這就可能造成一個線主存中修改了一個變量的值,而另外一個線程還繼續(xù)使用它在寄存器中的變量值的拷貝,造成據(jù)的不一致。要解決這個問題,就需要把變量為volatile,這就指示JVM,這個變量是不穩(wěn)定的,每次使用它都到主存中進行說白了,volatile關鍵字的主要作用就是保證變量的可見性然后還有一個作用是防止指令重排說說synchronized關鍵字和volatilesynchronized關鍵字和volatile關鍵字比ltile關鍵字是線程同步的輕量級實現(xiàn),所以voltile性能肯定比shonized關鍵字要好。但是voltile關鍵字只能用于變量而shonized關鍵字可以修飾方法以及代碼塊。synchonze關鍵字在JaSE1.6之后進行了主要包括為了減少獲得鎖和釋放鎖帶來的性能消耗而引入的偏向鎖和輕量級鎖以及其它各種優(yōu)化之后執(zhí)行效率有了顯著提升,實際開發(fā)中使用shonized關鍵字的場景還是一些。多線程volatile關鍵字不會發(fā)生阻塞,而synchronized關鍵字可能會發(fā)生阻ltile關鍵字能保證數(shù)據(jù)的可見性,但不能保證數(shù)據(jù)的原子性。synhonized關鍵字兩者都能保證。ltile關鍵字主要用于解決變量在多個線程之間的可見性,而nhonized線程池提供了一種限制和管理資源(包括執(zhí)行一個任務)。每個線程池還一些基本統(tǒng)計信息,例如已完成任務這里借用《Java并發(fā)編程的藝術》提到的來說一下使用線程池的好降低資源消耗。通過重復利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗。提高響應速度。任務到達時,任務可以不需要的等到線程創(chuàng)建就能立即執(zhí)行。提高線程的可管理性。線程是稀缺資源,如果的創(chuàng)建,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,使用線程池可以進行統(tǒng)一的分配,調(diào)優(yōu)和。實現(xiàn)Runnable接口和Callable接口的區(qū)如果想讓線程池執(zhí)行任務的話需要實現(xiàn)的Ruale接口或Calable接口。Runle接口或Calable接口實現(xiàn)類都可以被TheadPooEecutor或ScudTheadPooEecutor執(zhí)行。兩者的區(qū)別在于RunbeCalable接口可以返回結果。備注:工具類Executors可以實現(xiàn)Runnable對象和Callable對象之間的相互轉換Executors.callable(RunnableExecutors.callable(Runnable或Executors.callable(Runnabletask,Objectresule)) 方法用于提交不需要返回值的任務,所以無法判斷任務是否被線程池執(zhí)行成功與ub()方法用于提交需要返回值的任務。線程池會返回一個futue類型的對象,通過這個futue對象可以判斷任務是否執(zhí)行成功,并且可以通過ftue的g()方法來獲取返回值,g()方阻塞當前線程直到任務完成,而使用get(longtimeout,TimeUnit方法則會阻塞當前線程一段時間后立即返回get(longtimeout,TimeUnit《阿里巴巴Java開發(fā)手冊》中強制線程池不允許使用Executors去創(chuàng)建,而是通過ThreadPoolExecutor的方式,這Executors返回線程池對象的弊端如FixedThreadPool和SingleThreadExecutor:允許請求的隊列長度為Integer.MAX_VALUE,可能堆積CachedThreadPool和ScheduledThreadPool:允許創(chuàng)建的線程數(shù)量為Integer.MAX_VALUE,可能方式一:通過構造方法方式二:通過方式二:通過Executor框架的工具類Executors來實現(xiàn)我們可以創(chuàng)建三種類型的FiTheadPool:該方法返回一個固定線程數(shù)量的線程池。該線程池中的線程數(shù)量始終不變。當有一個新的任務提交時,線程池中若有空閑線程,則立即執(zhí)行。若沒有,則新的任務會被暫存在一個任務隊列中,待有線程空閑時,便處理在任務隊列中的任務。SingleThreadExecutor:方法返回一個只有一個線程的線程池。若多余一個任務被提交到該線程池,任務會CachedThdPool:該方法返回一個可根據(jù)實際情況調(diào)整線程數(shù)量的線程池。線程池的線程數(shù)量不確定,但若有空閑線程可以復用,則會優(yōu)先使用可復用的線程。若所有線程均在工作,又有新的任務提交,則會創(chuàng)建新的線程處理任務。所有線當前任務執(zhí)行完畢后,將返回線程池進行復用。對應Executors工具類中的方法如圖所示Atomic4介紹一下AtomicAtomic翻譯成中文是原子的意思。在化學上,我們知道原子是構成一般物質(zhì)的最小單位,在化學反應中是不可分割的。在我們這里Atomic是指一個操作是不可中斷的。即使是在多個線程一起執(zhí)行的時候,一個操作一旦開始,就不會被其他線程干擾。所以,所謂原子類說簡單點就是具有原子/原子操作特征的類并發(fā)

的原子類都存放

下,如下圖所JUC包中的原子類是哪4類基本類使用原子的方式更新基本類AtomicBoolean:布爾型原子類數(shù)組類使用原子的方式更新數(shù)組里的某個類AtomicReference:類型原子類AtomicStampedRerence:原子更新類型里的字段原子類 :原子更新帶有標記位的類對象的屬性修改類AtomicIntegerFieldUpdater:原子更新整形字段的更AtomicLongFieldUpdater:原子更新長整形字段的更AtomicStampedRefeence:原子更新帶有版本號的類型。該類將整數(shù)值與關聯(lián)起來,可用于解決原子的更新數(shù)據(jù)和數(shù)據(jù)的版本號,可以解決使用CAS進行原子更新時可能出現(xiàn)的AA問題。AtomicIntegerAtomicInteger類常用publicfinalintgetAndIncrement()//獲取當前的值,并自增publicfinalintgetAndDecrement()//publicfinalintgetAndAdd(intdelta)//獲取當前的值,并加上預期booleancompareAndSet(intexpect,intupdate)//如果輸入的數(shù)值等于預期值,則以原子方式將該值設置publicfinalvoidlazySet(intnewValue)//最終設置為newValue,lazySet設置之后可能導致其他線AtomicInteger類的使使用AtomicInteger之后,不用對increment()方法加鎖也可以保證線程安classclassAtomicIntegerTestprivateAtomicIntegercount=newpublicvoidincrement(){}publicintgetCount()return}}能不能給我簡單介紹一下AtomicIntegerAtomicInteger線程安全原理簡單分AtomicInteger類的部分源碼////setuptopareAndSwapIntforupdates(更新操作時提供“比較并替換”的作用privatestaticfinalUnsafeunsafe=Unsafe.getUnsafe();privatestaticfinallongvalueOffset;statictryvalueOffset=unsafe.objectFieldOffset}catch(Exceptionex){thrownewError(ex);}privatevolatileintAtomicInteger類主要利用CAS(compareandswap)+volatile和native方法來保證原子操作,從而synchronized的高開銷,執(zhí)行效率大為提CAS的原理是拿期望的值和原本的一個值作比較,如果相同則更新成新的值。UnSafe類的objectFieldO?set()方法是一個本地方法,這個方法是用來拿到“原來的值”的內(nèi)存地址,返回值是valueO?set。另外value是一個volatile變量,在內(nèi)存中可見,因此JVM可以保證任何時刻任何線程總能拿到該變量的值。關于Atomic原子類這部分內(nèi)容可以查看這篇文章:并發(fā)編程面試必備:JUC中的Atomic原子類總AQS介AQS的全稱為 QueuedSynchronizer),這個類在java.util.concurrent.locks包下面ReentrantLock,Semaphore,其他的諸如ReentrantReadWriock,SynchronousQueue,F(xiàn)utureTask等等皆是AQS原理分AQS原理這部分參考了部分博客,在5.2節(jié)末尾放了在面試中被問到并發(fā)知識的時候,大多都會被問到“請你說一下自己對于QS原理的理解”。下面給大家一個示例供大家參加,面試不是背題,大家一定要假如自己的思想,即使加入不了自己的思想也要保證自己能夠通俗的講出來而不是背出來。下面大部分內(nèi)容其實在AQS類注釋上已經(jīng)給出了,不過是英語比較吃力一點,感的話源碼AQS原理概QS思想是,如果被請求的共享資源空閑,則將當前請求資源的線程設置為有效的工作線程,并且將共享資源設置為鎖定狀態(tài)。如果被請求的共享資源被占用,那么就需要一套線程阻塞等待以及被喚醒時鎖分配的機制,這個機制QS是用CLH隊列鎖實現(xiàn)的,即將暫時獲取不到鎖的線程加入到隊列中。CLH(C,La,ndHagrst)隊列是一個虛擬的雙向隊列(虛擬的雙向隊列即不存在隊列實例,僅存在結點之間的關聯(lián)關系)。QS是將每條請求共享資源的線程封裝成一個H鎖隊列的一個結點(Node)的分配。看個 QueuedSynchronizer)原理圖privateprivatevolatileintstate;//共享變量,使用volatile狀態(tài)信息通過procted類型的getState,setState,compareAndSetState進行操protectedfinalint{return}//protectedfinalvoidsetState(int{state=}protectedfinalbooleancompareAndSetState(intexpect,intupdate){ pareAndSwapInt(this,stateOffset,expect,}AQS對資源的共享方AQS定義兩種資源共享Euve(獨占):只有一個線程能執(zhí)行,如RettLock:按照線隊列中的排隊順序,先到者先拿到鎖非公平鎖:當線程要獲取鎖時,無視隊列順序直接去搶鎖,誰搶到就是誰的(共享):多個線程可同時執(zhí)行,如Semaphore/CountDownLatch。SemaphoreCountDownLatCh、CyclicBarrier、 ock我們都會在后面講到 ock可以看成是組合式,因為ReentrantReadWri 不同的自定義同步器爭用共享資源的方式也不同。自定義同步器在實現(xiàn)時只需要實現(xiàn)共享資源state的獲取與釋放方AQS底層使用了模板方法同步器的設計是基于模板方法模式的,如果需要自定義同步器一般的方式是這樣(用): 將AQS組合在自定義同步組件的實現(xiàn)中,并調(diào)用其模板方法,而這些模板方調(diào)用使用者重寫的方法這和我們以往通過實現(xiàn)接口的方式有很大區(qū)別,這是模板方法模式很經(jīng)典的一個運AQS使用了模板方法模式,自定義同步器時需要重寫下面幾個AQS提供的模板方tryAcquireharein//默認情況下,每個方法都拋出UnsupportedOperatinException。這些方法的實現(xiàn)必須是線程安全的,并且通常應該簡短而不是阻塞。QS類中的其他方法都是?nl,所以無法被其他類使用,只有這幾個方法可以被其他類使用。RttLck為例,state初始化為0,表示未鎖定狀態(tài)。A線程ock()時,會調(diào)用tryAcqui獨占該鎖并將stt1。此后,其他線程再tryAcqui()時就會失敗,直到A線程nlck()stte=0(即釋放鎖)為止,其它線程才有機會獲取該鎖。當然,釋放鎖之前,A線程自己是可以重復獲取此鎖的(state會累加)state是能回到零態(tài)的。再以CountDwnLatch以例,任務分為N個子線程去執(zhí)行,state也初始化為N(注意N要與線程個數(shù)一致)。這N個子線程是并行執(zhí)行的,每個子線程執(zhí)行完后coutwn()一次,state會CAS(CompaeandSwa)減1。等到所有子線程都執(zhí)行完后(即state=0),會unpark()主調(diào)用線程,然后主調(diào)用線程就會從awit()函數(shù)返回,繼續(xù)后余動作。一般來說,自定義同步器要么是獨占方法,要么是共享方式,他們也只需實現(xiàn)tryAcquire-tryRelease中的一種即可。但AQS也支持自定義同步器同時實現(xiàn)獨占和共享兩種方如如 ock推薦兩篇AQS原理和相關源碼分析的AQSSemaphore(信號量)-允許多個線程同時:synchronized和ReentrantLock都是一次只允許一個線程某個資源,Semaphore(信號量)可以指定多個線程同時某個資源。CountDwnLch(倒計時器):CoutDwnLatch是一個同步工具類,用來協(xié)調(diào)多個線程之間的同步。這個工具通常用來控制線程等待,它可以讓某一個線程等待直到倒計時結束,再開始執(zhí)行。CyclicBarrie(循環(huán)柵欄):CyclicBrrir和CountDwnLatch非常類似,它也可以實現(xiàn)線程間的技術等待,但是它的功能比CountDwnLtch更加復雜和強大。主要應用場景和CountDwnLatch類似。CycicBarrier的字面意思是可循環(huán)使用(Cyclic)的屏障(Brer)。它要做的事情是,讓一組線程到達一個屏障(點)時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障的線程才會繼續(xù)干活。CyclicBrrir默認的構造方法是CyclicBarr(tpies),其參數(shù)表示屏障的線程數(shù)量,每個線程調(diào)用aat方法告訴CyclicBrrir我已經(jīng)到達了屏障,然后當前線程被阻塞。關于AQS這部分的內(nèi)容可以查看這篇文章:并發(fā)編程面試必備:AQS原理以及AQS同步組件總Java虛擬關于Java虛擬機,在面試的時候一般會問的大多就是①Java內(nèi)存區(qū)域、②虛擬機算法、③虛擬機收集器、④JVM內(nèi)存管理、⑤JVM調(diào)優(yōu)這些問題了。 具體可以查看這三篇文章:《深入理解Java虛擬機》第2版學習筆設計模式比較常見的就是讓你手寫一個單例模式(注意單例模式的幾種不同的實現(xiàn)方法)或者讓你說一下某個常見的設計模式在你的項目中是如何使用的,另外面試官還有可能問你抽象工廠和工廠方法模式的區(qū)別、工廠模式的思想這樣的問題。建議把模式、觀察者模式、(抽象)工廠模式好好看一下,這三個設計模式也很重要三TCP、UDP協(xié)議的區(qū)UDP在傳送數(shù)據(jù)之前不需要先建立連接,遠機在收到UDP報文后,不需要給出任何確認。雖然UDP不提供可靠交付,但在某些情況下UDP確是一種最有效的工作方式(一般用于即時通信),比如:語音、、直TCP提供面向連接的服務。在傳送數(shù)據(jù)之前必須先建立連接,數(shù)據(jù)傳送結束后要釋放連接。TCP不提供廣播或多播服務。由于TCP要提供可靠的,面向連接的服務(TCP的可靠體現(xiàn)在TCP在傳遞數(shù)據(jù)之前,會有三次握手來建立源),這一增加了許多開銷,如確認,流量控制,計時器以及連接管理等。這不僅使協(xié)議數(shù)據(jù)單元的首部增大很多,還要占用許多處理機資源。CP一般用于文件傳輸、發(fā)送和接收郵件、登錄等場景。在瀏覽器中輸入url地址->>好像最喜歡問這個問總體來說分為以下幾個過程DNSTCP連發(fā)送HTTP請服務器處理請求并返回HTTP報瀏覽器解析渲染頁連接結具體可以參考下面這篇文 各種協(xié)議與HTTP協(xié)議之間的關HTTP長連接、短在TTP/1.0中默認使用短連接。也就是說,客戶端和服務器每進行一次TTP操作,就建立一次連接,任務結束就中斷連接。當客戶端瀏覽器的某個HTML或其他類型的eb頁中包含有其他的eb資源(如JavaScrit文件、圖像文件、CSS文件等),每遇到這樣一個eb資源,瀏覽器就會重新建立一個TTP會話。而從HTTP/1.1起,默認使用長連接,用以保持連接特性。使用長連接的HTTP協(xié)議,會在響應頭加入這行代在使用長連接的情況下,當一個網(wǎng)頁打開完成后,客戶端和服務器之間用于傳輸HTTP數(shù)據(jù)的CP連接不會關閉,客戶端再次這個服務器時,會繼續(xù)使用這一條已經(jīng)建立的連接。Keep-Alve不會保持連接,它有一個保持時間,可以在不同的服務器軟件(如Apache)中設定這個時間。實現(xiàn)長連接需要客戶端和服務端都支持長連接。HTTP協(xié)議的長連接和短連接,實質(zhì)上是TCP協(xié)議的長連接和短連——《HTTP長連接、短連接究竟是什么 三次握手和四次揮手(面試常客來源:《圖解HTTP來源:《圖解HTTP簡單示意圖客戶端–發(fā)送帶有SYN標志的數(shù)據(jù)包–一次握手–服務服務端–發(fā)送帶有SYN/ACK標志的數(shù)據(jù)包–二次握手–客戶端客戶端–發(fā)送帶有帶有ACK標志的數(shù)據(jù)包–三次握手–服務端為什么要三次握手三次握手的目的是建立可靠的通信信道,說到通訊,簡單來說就是數(shù)據(jù)的發(fā)送與接收,而三次握手最主要的目的就是雙方確認自己與對方的發(fā)送與接收是正常的。第一次握手:Client什么都不能確認;Server確認了對方發(fā)送正第二次握手:Client確認了:自己發(fā)送、接收正常,對方發(fā)送、接收正常;Server確認了:自己接收正常,對方發(fā)第三次握手:Client確認了:自己發(fā)送、接收正常,對方發(fā)送、接收正常;Server確認了:自己發(fā)送、接收正常,為什么要傳回SYN接收端傳回發(fā)送端所發(fā)送的SYN是為了告訴發(fā)送端,我接收到的信息確實就是你所發(fā)送的信號SYN是CP/IP建立連接時使用的握手信號。在客戶機和服務器之間建立正常的CP網(wǎng)絡連接時,客戶機首先發(fā)出一個SYN消息,服務器使用SYN-CK應答表示接收到了這個消息,最后客戶機再以CK(Acknldeme[漢譯:確認字符,在數(shù)據(jù)通信傳輸中,接收站發(fā)給發(fā)送站的一種傳輸控制字符。它表示確認發(fā)來的數(shù)據(jù)已經(jīng)接受無誤。])消息響應。這樣在客戶機和服務器之間才能建立起可靠的CP-傳了SYN,為啥還要傳雙方通信無誤必須是兩者互相發(fā)送信息都無誤。傳了SYN,證明發(fā)送方到接收方的通道沒有問題,但是接收方到發(fā)送方的通道還需要ACK信號來進行驗證。斷開一個TCP連接則需要“四次揮手客戶端-發(fā)送一個FIN,用來關閉客戶端到服務器的數(shù)據(jù)傳服務器-收到這個FIN,它發(fā)回一ACK,確認序號為收到的序號加1。和SYN一樣,一個FIN將占用一個序號客戶端-發(fā)回ACK報文確認,并將確認序號設置為收到序號加1任何一方都可以在數(shù)據(jù)傳送結束后發(fā)出連接釋放,待對方確認后進入半關閉狀態(tài)。當另一方也沒有數(shù)據(jù)再發(fā)送舉個例子:A和B打,通話即將結束后,A說“我沒啥要說的了”,B回答“我知道了”,但是B可能還會有要說的話,A不能要求B跟著自己的節(jié)奏結束通話,于是B可能又巴拉巴拉說了一通,最后B說“我說完了”,A回答“知道上面講的比較概括,推薦一篇講的比較細致的文簡單介紹一下LinuxLinux文件系統(tǒng)簡在Linux操作系統(tǒng)中,所有作系統(tǒng)管理的資源,例如網(wǎng)絡接口卡、磁盤驅(qū)動器、、輸入輸出設備、普通文件或是 都被看作是一個文件。也就是說在LINU

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論