Java面試個人總結200多題(四)

聲明:
這是個人面試的總結,很多都是我自己百度的,答案只供大家參考。哈哈,後面是個人被問過的一些題。 就不做整理了,大家將就看看。如果覺得有問題大家也可以百度補充。

十八、Redis
Redis更要多懂一點,單線程模型,aof,rdb,rewrite,主從,cluster,哪些類型?包含一些緩存常見的問題擊穿、穿透、雪崩、數據一致性等

179.redis 是什麼?都有哪些使用場景?
Redis是一個開源的 key—value型 單線程 數據庫,支持string、list、set、zset和hash類型數據。
使用場景:
1.熱點數據緩存
2.排行榜
3.點贊,好友
4.隊列
5.定時器,計數器
6.發佈訂閱消息

180.redis 有哪些功能?
持久化,哨兵,複製,集羣
181.redis 和 memecache 有什麼區別?
1、存儲方式:
memecache 把數據全部存在內存之中,斷電後會掛掉,數據不能超過內存大小
redis有部份存在硬盤上,這樣能保證數據的持久性。
2、數據支持類型:
redis在數據支持上要比memecache多的多。
3、使用底層模型不同:
新版本的redis直接自己構建了VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
4、運行環境不同:
redis目前官方只支持LINUX 上去行,從而省去了對於其它系統的支持,這樣的話可以更好的把精力用於本系統 環境上的優化,雖然後來微軟有一個小組爲其寫了補丁。但是沒有放到主幹上

182.redis 爲什麼是單線程的?
因爲Redis是基於內存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內存的大小或者網絡帶寬
183.什麼是緩存穿透?怎麼解決?
緩存穿透是指查詢一個一定不存在的數據,由於緩存是不命中時需要從數據庫查詢,查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到數據庫去查詢,造成緩存穿透。
解決:
1.布隆過濾
對所有可能查詢的參數以hash形式存儲,在控制層先進行校驗,不符合則丟棄。還有最常見的則是採用布隆過濾器,將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。
2. 緩存空對象. 將 null 變成一個值.
也可以採用一個更爲簡單粗暴的方法,如果一個查詢返回的數據爲空(不管是數 據不存在,還是系統故障),我們仍然把這個空結果進行緩存,但它的過期時間會很短,最長不超過五分鐘。

什麼是緩存雪崩?
如果緩存集中在一段時間內失效,發生大量的緩存穿透,所有的查詢都落在數據庫上,造成了緩存雪崩。
184.redis 支持的數據類型有哪些?
5種數據類型,list,set,zset,hash,string
185.redis 支持的 java 客戶端都有哪些?
Redisson,Jedis,lettuce等等,官方推薦使用Redisson。
186.jedis 和 redisson 有哪些區別?
Jedis是Redis的java實現客戶端,其API提供了比較全面的Redis命令的支持;Redisson實現了分佈式和可擴展的Java數據結構,和Jedis相比,功能較爲簡單,不支持字符串操作,不支持排序、事務‘管道、分區等Redis特性。Redisson的宗旨是促進使用者對Redis的關注分離,從而讓使用者能夠將精力更集中地放在處理業務邏輯上
187.怎麼保證緩存和數據庫數據的一致性?
方案一:讀寫分離
讀請求只訪問緩存,寫請求只修改數據庫和緩存
方案二:隊列存儲請求
但是倘若訪問量大,處理器來不及處理,隊列內的請求數量越來越高,則會影響查詢效率。出現這種情況,就要加機器集羣執行,幫忙分擔壓力
188.redis 持久化有幾種方式?
AOF:將收到每一個寫命令通過write函數追加到文件最後
RDB:是redis默認的持久化機制,通過快照方式保存到二進制文件中

189.redis 怎麼實現分佈式鎖?

190.redis 分佈式鎖有什麼缺陷?
191.redis 如何做內存優化?
一. redisObject對象
二. 縮減鍵值對象
三. 共享對象池
四. 字符串優化
五. 編碼優化
六. 控制key的數量
192.redis 淘汰策略有哪些?
volatile-lru: 從已經設置過期時間的數據集中,挑選出最近最少使用的進行淘汰
volatile-ttl: 從已經設置過期時間的數據集中,挑選出過期的進行淘汰
volatile-random: 從已經設置過期時間的數據集中,任意進行淘汰
allkeys-lru: 從數據集中挑選最近最少使用的進行淘汰
allkeys-random: 從數據集中挑選,任意進行淘汰
noveviction:不淘汰策略,超過內存限制,直接報錯

193.redis 常見的性能問題有哪些?該如何解決?
1.Master寫內存快照,save命令調度rdbSave函數,會阻塞主線程的工作,當快照比較大時對性能影響是非常大的,會間斷性暫停服務,所以Master最好不要寫內存快照。
2.Master AOF持久化,如果不重寫AOF文件,這個持久化方式對性能的影響是最小的,但是AOF文件會不斷增大,AOF文件過大會影響Master重啓的恢復速度。
3.Master調用BGREWRITEAOF重寫AOF文件,AOF在重寫的時候會佔大量的CPU和內存資源,導致服務load過高,出現短暫服務暫停現象。
4.Redis主從複製的性能問題
5.單點故障問題

194.哈希槽概念?
redis有16384個哈希槽,通過crc16校驗後對16384取模來決定放在哪個槽,集羣每一個節點負責一個hash槽;

195.redis事務相關命令?
watch exec discard multl

196.redis設置過期時間和永久有效命令?
expire 和 persist

197.緩存雪崩?
原有的緩存失效,新的緩存未到期

redis的持久化RDB和AOF?
RDB默認的持久化方式,通過快照方式存儲到二進制文件中
AOF默認不開啓,將每一個收到的寫命令,通過write函數追加到文件中

十九、JVM
194.說一下 jvm 的主要組成部分?及其作用?
線程私有:
程序計數器:
當前線程執行的字節碼行號指示器
虛擬機棧:
虛擬機棧中執行每個方法的時候,都會創建一個棧幀用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息
本地方法棧:
與虛擬機棧的作用是一樣的,只不過虛擬機棧是服務Java方法的,而本地方法棧是爲虛擬機調用Native方法服務的。

線程共享:
堆:
堆是Java對象的存儲區域,任何用new字段分配的Java對象實例和數組,都被分配在堆上,Java堆可使用-Xms -Xmx進行內存控制,值得一提的是從JDK1.7版本之後,運行時常量池從方法區移到了堆上。
方法區:
它用於存儲已被虛擬機加載的類信息,常量,靜態變量,即時編譯器編譯後的代碼等數據,方法區在JDK1.7版本及以前被稱爲永久代,從JDK1.8永久代被移除。

195.說一下 jvm 運行時數據區?
196.說一下堆棧的區別?
1.棧內存存儲的是局部變量而堆內存存儲的是實體;
2.棧內存的更新速度要快於堆內存,因爲局部變量的生命週期很短;
3.棧內存存放的變量生命週期一旦結束就會被釋放,而堆內存存放的實體會被垃圾回收機制不定時的回收。
197.隊列和棧是什麼?有什麼區別?
隊列(Queue):是限定只能在表的一端進行插入和另一端刪除操作的線性表
棧(Stack):是限定之能在表的一端進行插入和刪除操作的線性表

隊列:先進先出
棧:先進後出
198.什麼是雙親委派模型?
當需要加載一個類的時候,子類加載器並不會馬上去加載,而是依次去請求父類加載器加載,一直往上請求到最高類加載器:啓動類加載器。當啓動類加載器加載不了的時候,依次往下讓子類加載器進行加載。當達到最底下的時候,如果還是加載不到該類,就會出現ClassNotFound的情況。
199.說一下類加載的執行過程?
加載:將java源代碼編譯後的.class字節碼文件以二進制流的方式加載進內存
連接
驗證:驗證加載進來的二進制流是否符合虛擬機的規範,不會危害的虛擬機自身的安全

   準備:給類變量(靜態變量)賦予初始值,基本數據/引用類型數據

   解析:將字符串引用轉換爲直接引用

初始化:變量賦予初始值、執行靜態語句塊、執行構造函數等等

200.怎麼判斷對象是否可以被回收?
引用計數:
就是給對象添加一個引用計數器,每當有一個地方引用這個對象時,計數器值加1,每當一個引用失效時,計數器減1,任何時刻計數器爲0的對象就是不可能再被使用的。
可達性分析算法:
當一個對象到GC Roots沒有任何引用鏈相連時(圖論裏面專業一點來說,就是從GC Roots到這個對象不可達),則證明對象是不可用的

201.java 中都有哪些引用類型?
強引用,弱引用,軟引用,虛引用
202.說一下 jvm 有哪些垃圾回收算法?
A。標記整理法:標記所有對象,讓存活的對象向一端移動,回收端邊界外的所有對象
B。標記清除法:標記所有的回收對象,統一回收
C。複製算法:將內存劃分爲一塊較大的eden區,和兩塊較小的From和To 區,
203.說一下 jvm 有哪些垃圾回收器?
Serial(串行GC)-複製
ParNew(並行GC)-複製
Parallel Scavenge(並行回收GC)-複製
Serial Old(MSC)(串行GC)-標記-整理
CMS(併發GC)-標記-清除
Parallel Old(並行GC)–標記-整理
G1(JDK1.7update14纔可以正式商用)
204.詳細介紹一下 CMS 垃圾回收器?
最短回收停頓時間,適用於重視響應速度的服務器。
過程:
初始標記–併發標記–重新標記–併發清除
優點:併發收集----低停頓
缺點:產生碎片,對cpu敏感,佔用cpu,導致程序變慢。無法處理浮動垃圾;
標記清除法

20X.詳細介紹下G1垃圾回收器?
並行併發,分代收集,不需要和其他收集器配合,獨立管理GC堆,不產生碎片
過程:
初始標記,併發標記,最終標記,篩選回收
標記整理法

205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什麼區別?
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
206.簡述分代垃圾回收器是怎麼工作的?

207.說一下 jvm 調優的工具?
VisualVM , jdk自帶的工具jconsole
208.常用的 jvm 調優的參數都有哪些?
1、-Xms
s爲strating,表示堆內存起始大小
2、-Xmx
x爲max,表示最大的堆內存
(一般來說-Xms和-Xmx的設置爲相同大小,因爲當heap自動擴容時,會發生內存抖動,影響程序的穩定性)

3、-Xmn
n爲new,表示新生代大小
(-Xss:規定了每個線程虛擬機棧(堆棧)的大小)
4、-XX:SurvivorRator=8
表示堆內存中新生代、老年代和永久代的比爲8:1:1
5、-XX:PretenureSizeThreshold=3145728
表示當創建(new)的對象大於3M的時候直接進入老年代
6、-XX:MaxTenuringThreshold=15
表示當對象的存活的年齡(minor gc一次加1)大於多少時,進入老年代
7、-XX:-DisableExplicirGC
表示是否(+表示是,-表示否)打開GC日誌

簡述下垃圾回收機制?
在jvm中有一個垃圾回收線程,它是低優先級的,正常情況下不會執行,只有等到虛擬機空閒的時候,或者內存不足時纔會執行,掃描那些沒有被引用的對象,添加到回收集合中,統一進行回收;

簡述下類加載機制?
虛擬機將類的.class文件加載到內存中,對數據進行加載,驗證,準備,解析,初始化,最終形成被虛擬機直接使用的java類型

如何打破雙親委派機制?
要繼承classLoader類,還要重寫loadClass 和findClass

新生代垃圾回收的執行過程:
1、Eden 區 + From Survivor 區存活着的對象複製到 To Survivor 區;
2、清空 Eden 和 From Survivor 分區;
3、From Survivor 和 To Survivor 分區交換(From 變 To,To 變 From)。

集合:(*****)
HashMap的結構
HashMap的底層主要是基於數組和鏈表來實現的,它之所以有相當快的查詢速度主要是因爲它是通過計算散列碼來決定存儲的位置。HashMap中主要是通過key的hashCode來計算hash值的,只要hashCode相同,計算出來的hash值就一樣。如果存儲的對象對多了,就有可能不同的對象所算出來的hash值是相同的,這就出現了所謂的hash衝突。學過數據結構的同學都知道,解決hash衝突的方法有很多,HashMap底層是通過鏈表來解決hash衝突的。

爲什麼會死循環
如果擴容前相鄰的兩個Entry在擴容後還是分配到相同的table位置上,就會出現死循環的BUG。
hashmap是線程不安全的,最好不要在併發情況下使用;
如果想在併發情況下使用可以用:
1.ConcurrentHashMap
2.使用Collections.synchronizedMap(Mao<K,V> m)方法把HashMap變成一個線程安全的Map。

1.7和1.8的區別
A。1.7 用的是數組加鏈表,1.8加入 紅黑樹,當鏈表個數大於8時會轉換成紅黑樹,小於8時轉換成鏈表
B。1.7採用的是頭插法,1.8採用的是尾插法
C。

1.8加入紅黑樹解決了什麼
A。由於在JDK1.7之前,HashMap的數據結構爲:數組 + 鏈表。數組相當於日常中永到的數據結構Array. 用來確定key-value對所存儲的位置。如果按照Hash值,通過Hash函數來確認桶位,會存在一個問題,就是hash衝突的問題,也就是不同的key可能會產生不一樣的hash值。

B。所以引入了鏈表來存儲hash值一樣的key-value. 如果按照鏈表的方式存儲,隨着節點的增加數據會越來越多,這會導致查詢節點的時間複雜度會逐漸增加,平均時間複雜度O(n)。 爲了提高查詢效率,故在JDK1.8中引入了改進方法紅黑樹。此數據結構的平均查詢效率爲O(long n) 。

1.8還有死循環問題嗎
如何解決死循環問題

答:從JDK1.8開始修復了死循環問題,不再是頭插方式,而是後插入的放在尾部,比如插入順序是1,2,3 ,則鏈表結構爲1----》2----》3----》null ,並且擴容後不再是一邊遍歷一邊從共享數組中取值,二是組裝完畢鏈表後直接賦值給共享數組。

ConcurrentHashMap的結構, 和HashTable對比
⑴ HashTable的線程安全使用的是一個單獨的全部Map範圍的鎖,ConcurrentHashMap拋棄了HashTable的單鎖機制,使用了鎖分離技術,使得多個修改操作能夠併發進行,只有進行SIZE()操作時ConcurrentHashMap會鎖住整張表。
⑵ HashTable的put和get方法都是同步方法, 而ConcurrentHashMap的get方法多數情況都不用鎖,put方法需要鎖。
但是ConcurrentHashMap不能替代HashTable,因爲兩者的迭代器的一致性不同的,hash table的迭代器是強一致性的,而concurrenthashmap是弱一致的。 ConcurrentHashMap的get,clear,iterator 都是弱一致性的。

ConcurrentHashMap爲什麼性能高
答:ConcurrentHashMap裏使用了Segment分段鎖+HashEntry,而HashTable用的是Syncronized鎖全部,所有線程競爭一把鎖。
Segment分段鎖繼承ReentrantLock,在併發數高的時候,ReentrantLock比Syncronized總體開銷要小一些

ConcurrentHashMap1.7和1.8的區別
1、整體結構
1.7:Segment + HashEntry + Unsafe
1.8: 移除Segment,使鎖的粒度更小,Synchronized + CAS + Node + Unsafe

2、put()
1.7:先定位Segment,再定位桶,put全程加鎖,沒有獲取鎖的線程提前找桶的位置,並最多自旋64次獲取鎖,超過則掛起。
1.8:由於移除了Segment,類似HashMap,可以直接定位到桶,拿到first節點後進行判斷,1、爲空則CAS插入;2、爲-1則說明在擴容,則跟着一起擴容;3、else則加鎖put(類似1.7)

3、get()
基本類似,由於value聲明爲volatile,保證了修改的可見性,因此不需要加鎖。
4、resize()
1.7:跟HashMap步驟一樣,只不過是搬到單線程中執行,避免了HashMap在1.7中擴容時死循環的問題,保證線程安全。
1.8:支持併發擴容,HashMap擴容在1.8中由頭插改爲尾插(爲了避免死循環問題),ConcurrentHashmap也是,遷移也是從尾部開始,擴容前在桶的頭部放置一個hash值爲-1的節點,這樣別的線程訪問時就能判斷是否該桶已經被其他線程處理過了

java中error和exception的區別?
Error類一般是指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,內存空間不足,方法調用棧溢等
Exception類表示程序可以處理的異常,可以捕獲且可能恢復。遇到這類異常,應該儘可能處理異常,使程序恢復運行,而不應該隨意終止異常。

hashcode的作用?
hashCode可以將集合分成若干個區域,每個對象都可以計算出他們的hash碼,可以將hash碼分組,每個分組對應着某個存儲區域,根據一個對象的hash碼就可以確定該對象所存儲區域,這樣就大大減少查詢匹配元素的數量,提高了查詢效率

spirngboot的自動裝配:
配置文件定義屬性,自動裝配到所屬依賴的一個類裏面,然後通過ioc,再以他的這種動態代理方式,注入到他spring的容器裏去

  1. 對外提供接口的api如何保證冪等
    如銀聯提供的付款接口:需要接入商戶提交付款請求時附帶:source來源,seq序列號
    source+seq在數據庫裏面做唯一索引,防止多次付款,(併發時,只能處理一個請求)

重點:
對外提供接口爲了支持冪等調用,接口有兩個字段必須傳,一個是來源source,一個是來源方序列號seq,這個兩個字段在提供方系統裏面做聯合唯一索引,這樣當第三方調用時,先在本方系統裏面查詢一下,是否已經處理過,返回相應處理結果;沒有處理過,進行相應處理,返回結果。注意,爲了冪等友好,一定要先查詢一下,是否處理過該筆業務,不查詢直接插入業務系統,會報錯,但實際已經處理了

Java的四大基礎特性

一、抽象
父類爲子類提供一些屬性和行爲,子類根據業務需求實現具體的行爲。

抽象類使用abstract進行修飾,子類要實現所有的父類抽象方 法否則子類也是抽象類。
二、封裝
把對象的屬性和行爲(方法)結合爲一個獨立的整體,並儘可能隱藏對象的內部實現細節;
在java中,對於對象的內部屬性一般用private來實現隱藏,並通過set和get方法對外提供訪問接口。

三、繼承
子類繼承父類的屬性和行爲,並能根據自己的需求擴展出新的屬性和行爲,提高了代碼的可複用性。
Java的繼承通過extends關鍵字來實現,實現繼承的類被稱爲子類,被繼承的類稱爲父類(有的也稱其爲基類、超類),父類和子類的關係,是一種一般和特殊的關係;子類擴展父類,將可以獲得父類的全部屬性和方法。

overide:
當子父類中出現相同方法時,會先運行子類中的方法。
重寫的特點:方法名一樣,訪問修飾符權限不小於父類,返回類型一致,參數列表一致。
四、多態
不修改程序代碼就可以改變程序運行時所綁定的具體代碼,讓程序可以選擇多個運行狀態;
具體的實現方式就是:接口實現,繼承父類進行方法重寫,同一個類中進行方法重載。

一個對象變量可以指示多種實際類型的現象被稱爲多態。
不同類的對象對同一消息作出不同的響應就叫做多態。
所謂的多態就是對一個實例的相同方法在不同的情況下有不同表現形式

封裝和繼承都是爲Java語言的多態提供了支撐;多態存在的三個必要條件:
要有繼承;
要有重寫;
父類引用指向子類對象。

JDK1.7 和jdk 1.8 map
java中有哪些引用類型?
強引用:發生GC時不會被回收
軟引用:發生內存溢出時會被GC回收
弱引用:在下一次gc時會被回收
虛引用:用途是在gc時返回一個通知

mybatis 一對多 ,多對一
內存溢出和內存泄漏?
內存溢出就是程序要求的內存超過系統分配的內存;
內存泄漏:程序申請內存後,無法釋放已經申請的內存;

多線程的好處:
1.使用線程可以把佔據時間長的程序中的任務放到後臺去處理
2.用戶界面更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某件事件的處理,可以彈出一個進度條來顯示處理的進度
3.程序的運行效率可能會提高
4.在一些等待的任務實現上如用戶輸入,文件讀取和網絡收發數據等,線程就比較有用了.

多線程的缺點:
1.如果有大量的線程,會影響性能,因爲操作系統需要在它們之間切換.
2.更多的線程需要更多的內存空間
3.線程中止需要考慮對程序運行的影響.
4.通常塊模型數據是在多個線程間共享的,需要防止線程死鎖情況的發生

傳值 和傳引用的區別?
傳值:實參傳遞給形參的是一個副本,在方法中修改的話不會影響實參
傳引用:傳遞的是一個地址值,在方法中修改,實參的值也會跟着改變

方法重載和方法重寫的區別
方法重載:在一個類中,方法名相同,方法的參數類型,順序,個數不同
方法重寫:發生在子類繼承父類,方法名,參數類型,個數,返回值類型相同

被static關鍵字修飾的不需要創建對象去調用,直接根據類名就可以去訪問。
A。修飾變量,爲全局變量,屬於類中的所有對象,在內存中只有一個副本;
B。修飾方法,爲靜態方法,在靜態方法中不能調用類中非靜態的方法和變量
C。靜態代碼塊,用於類的初始化操作,可以用來優化程序性能
obeject常用的方法有:
toString() , getClass() ,equalse() , finalize() ,clone() , hashCode() ,notify() ,notifyAll() ,wait()

在瀏覽器輸入地址的請求流程:
域名解析 --> 發起TCP的3次握手 --> 建立TCP連接後發起http請求 --> 服務器響應http請求,瀏覽器得到html代碼 --> 瀏覽器解析html代碼,並請求html代碼中的資源(如js、css、圖片等) --> 瀏覽器對頁面進行渲染呈現給用戶

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章