互聯網公司java面試題(一)


1、JDK和JRE區別?

JDK是整個JAVA的核心,包括了Java運行環境JRE,一堆Java工具和Java基礎的類庫。
通過JDK開發人員將源碼文件(java文件)編譯成字節碼文件(class文 件)。
JRE是Java運行環境,不含開發環境,即沒有編譯器和調試器。將class文件加載到內存准備運行。

 

2、final關鍵字,抽象類可以使用final修飾嗎? 

1.用來修飾數據,包括成員變量和局部變量,該變量只能被賦值一次且它的 值無法被改變。對於成員變量來講,必須在聲明時或者構造方法中對它賦值;
2.修飾方法,表示該方法無法被重寫;
3.修飾類,表示該類無法被繼承。

注:抽象類是被用於繼承的,final修飾代表不可修改、不可繼承的。所以不能用final修飾抽象類。

 

3、JAVA容器

(1)ArrayList底層數組實現,封裝了常見的增刪改查操作,並且支持動態擴容。適合查找多的場合。
(2)LinkedList基於鏈表實現的列表。適合增刪情況較多的場合。
(3)TreeSet,基於二叉排序樹(紅黑樹)實現的。TreeSet里最典型的就是它用到了兩種排序方式,即基於元素對象自身的實現的Comparable接口的自然排序,以及基於更為靈活不與單個元素綁定的Comparator接口的客戶化排序。自己在構造的時候傳入一個比較器即可。
(4)HashMap是用來存儲鍵值對的映射關系,底層是用數組+鏈表實現的。結合put操作講一下。
(5)HashSet其實就是基於HashMap實現的,只不過將值固定為一個固定的值。
(6)LinkedHashMap,支持按照插入順序排序。
(7)PriorityQueue優先級隊列,一個基於優先級堆的無界優先級隊列 

 

4、多線程安全在三個方面體現:

1.原子性:提供互斥訪問,同一時刻只能有一個線程對數據進行操作; 
2.可見性:一個線程對主內存的修改可以及時地被其他線程看到;
3.有序性:程序執行的順序按照代碼的先后順序執行,由於指令重排序,結果一般雜亂無序。

 

5、JAVA怎么保證線程安全?

(1)保證原子性
   常用的保證Java操作原子性的工具是鎖和同步方法(或者同步代碼塊)。
   
   使用鎖,可以保證同一時間只有一個線程能拿到鎖,也就保證了同一時間只有一個線程能執行申請鎖和釋放鎖之間的代碼。
   
   與鎖類似的是同步方法或者同步代碼塊。
   使用非靜態同步方法時,鎖住的是當前實例;使用靜態同步方法時,鎖住的是該類的Class對象;使用靜態代碼塊時,鎖住的是synchronized關鍵字后面括號內的對象。
   
   無論使用鎖還是synchronized,本質都是一樣,通過鎖來實現資源的排性,從而實際目標代碼段同一時間只會被一個線程執行,進而保證了目標代碼段的原子性。這是一種以犧牲性能為代價的方法。

(2)保證可見性 
   Java提供了volatile關鍵字來保證可見性。
   由於JMM是基於共享內存實現線程通信的,所以會存在緩存一致性的問題。
   當使用volatile修飾某個變量時,它會保證對該變量的修改會立即被更新到內存中,並且將其它緩存中對該變量的緩存設置成無效。
   因此其它線程需要讀取該值時必須從主內存中讀取,從而得到最新的值。 (3)保證順序性
   編譯器和處理器對指令進行重新排序時,會保證重新排序后的執行結果和代碼順序執行的結果一致,所以重新排序過程並不會影響單線程程序的執行,卻可能影響多線程程序並發執行的正確性。
   Java中可通過volatile在一定程序上保證順序性,另外還可以通過synchronized和鎖來保證順序性。
   synchronized和鎖保證順序性的原理和保證原子性一樣,都是通過保證同一時間只會有一個線程執行目標代碼段來實現的。
   除了從應用層面保證目標代碼段執行的順序性外,JVM還通過被稱為happens-before原則隱式地保證順序性。
   兩個操作的執行順序只要可以通過happens-before推導出來,則JVM會保證其順序性,反之JVM對其順序性不作任何保證,可對其進行任意必要的重新排序以獲取高效率。

 

6、有沒有其他方法保證線程安全?

有。盡可能避免引起非線程安全的條件——共享變量。
如果能從設計上避免共享變量的使用,即可避免非線程安全的發生,也就無須通過鎖或者synchronized以及volatile解決原子性、可見性和順序性的問題。
還有不可變對象可以使用final修飾的對象保證線程安全,由於final修飾的引用型變量(除String外)不可變是指引用不可變,但其指向的對象是可變的,所以此類必須安全發布,即不能對外提供可以修改final對象的接口。

 

7、JAVA怎么避免死鎖?

1、加鎖順序 
當多個線程需要相同的一些鎖,但是按照不同的順序加鎖,死鎖就很容易發生。如果能確保所有的線程都是按照相同的順序獲得鎖,那么死鎖就不會發生。
2、加鎖時限 
在嘗試獲取鎖的時候加一個超時時間,這也就意味着在 嘗試獲取鎖的過程中若超過了這個時限該線程則放棄對該鎖請求。若一個線程沒有在給定的時限內成功獲得所有需要的鎖,則會進行回退並釋放所有已經獲得的鎖,然后等待一段隨機的時間再重試。這段隨機的等待時間讓其它線程有機會嘗試獲取相同的這些鎖,並且讓該應用在沒有獲得鎖的時候可以繼續運行。
3、死鎖檢測
死鎖檢測是一個更好的死鎖預防機制,它主要是針對那些不可能實現按序加鎖並且鎖超時也不可行的場景。每當一個線程獲得了鎖,會在線程和鎖相關的數據結構中(map、graph等等)將其記下。
除此之外,每當有線程請求鎖,也需要記錄在這個數據結構中。當一個線程請求鎖失敗時,這個線程可以遍歷鎖的關系圖看看是否有死鎖發生。
那么當檢測出死鎖時,這些線程該做些什么呢?一個可行的做法是釋放所有鎖,回退,並且等待一段隨機的時間后重試。
這個和簡單的加鎖超時類似,不一樣的是只有死鎖已經發生了才回退,而不會是因為加鎖的請求超時了。 雖然有回退和等待,但是如果有大量的線程競爭同一批鎖,它們還是會重復地死鎖。一個更好的方案是給這些線程設置優先級,讓一個(或幾個)線程回退,剩下的線程就像沒發生死鎖一樣繼續保持着它們需要的鎖。如果賦予這些線程的優先級是固定不變的,同 一批線程總是會擁有更高的優先級。為避免這個問題,可以在死鎖發生的時候設置隨機的優先級。

 

8、數據庫為什么建立索引?

優點:
    第一,通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。
    第二,可以大大加快數據的檢索速度,這也是創建索引的最主要的原因。
    第三,可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。
    第四,在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。
    第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。
缺點:
    第一,創建索引和維護索引要耗費時間,這種時間隨着數據量的增加而增加。
    第二,索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會更大。
    第三,當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。
適合應用索引的:經常需要搜索的列上,經常需要范圍查詢的,主鍵等。
不適合引用索引的:經常不用來查詢的,大字段的比如text段等。

 

9、硬盤里一個50G大小的文件和另一個100G文件,里面存儲着不同的名字,如何在一個內存很小的電腦上實現兩個文件的交集運算。

方法一:先用哈希切分,再用分桶+組內Hash索引的方法
將一個大文件里的數據使用一個哈希函數進行切分為許多小的文件,這樣相同的數據一定會進入同一個文件當中去,並進行文件編號。
對另外一個文件也是用相同的哈希函數進行切分為相同數目的小文件,這樣我們只需要將相同編號里的文件進行比較。這樣其時間復雜度就會降低為 O(n)。
相同的文件查找時可以先對一個文件建立hash索引(桶+鏈表),然后對另一個文件依次按照索引進行查找。若hash值相同在進行進一步比較即可。
方法二:位圖方法 O(n) 這有個前提是文件中必須存儲的是數字。那么根據位圖,我們可以將第一個文件中所有數據映射到位圖中去。
然后再不斷導入第二個文件,如果發現某個數字已經存儲在位圖中,就說明這是兩個文件的交集。
方法三:近似解-布隆過濾器 O(n) 將A文件每個數據經過多個Hash函數映射到一個位圖上,然后第二個文件同 樣的做法,如果全部命中,說明相同。否則說明不存在。但是這個有一定的錯誤率。
方法四:多路歸並排序 Onlog(n)+O(n) 先將文件划分為很多等量的小文件。然后對每個小文件導入內存進行內部排 序。這樣就有了很多有序的小文件。
然后對很多有序的小文件進行多路歸並排序,然后不斷寫入大文件即可。(Onlog(n))最終就得到了一個有序的大文件。最后對兩個有序的大文件進行查找相同的值即可(O(n))。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM