1.Redis面試題
1.說說你項(xiàng)目中redis的應(yīng)用場景
說一個(gè)redis的應(yīng)用場景,業(yè)務(wù)埋點(diǎn)
2.redis是單線程還是多線程
無論什么版本,工作線程是一個(gè)。6.X高版本出現(xiàn)了IO多線程。IO多線程依賴epoll進(jìn)行多線程讀取和輸出,更多壓榨服務(wù)器性能
3.說說pipeline,lua腳本,事務(wù)
redis命令都是原子執(zhí)行的,pipeline是客戶積攢了一堆命令,發(fā)送到服務(wù)端,但是這些命令不會(huì)一起執(zhí)行。redis事務(wù)是開啟事務(wù),然后命令都緩存到服務(wù)器隊(duì)列,客戶端發(fā)送執(zhí)行命令的時(shí)候,隊(duì)列的所有命令依次執(zhí)行,如果有失敗跳過,執(zhí)行下一個(gè)redis命令。lua腳本是原子的
4.緩存穿透,擊穿,雪崩
穿透:數(shù)據(jù)不存在請(qǐng)求打到數(shù)據(jù)庫,只讓一個(gè)請(qǐng)求到數(shù)據(jù)庫,查詢不到數(shù)據(jù)redis塞一個(gè)空,或者直接布隆過濾器過濾(布隆過濾器說不存在,肯定是不存在)。
擊穿:如果預(yù)知哪些是熱點(diǎn)數(shù)據(jù),可以value里面帶一個(gè)時(shí)間,比過期時(shí)間短。取到數(shù)據(jù)發(fā)現(xiàn)快要過期了,一個(gè)線程加鎖去取數(shù)據(jù),其他線程返回舊數(shù)據(jù)。如果不能預(yù)知哪些是熱點(diǎn)數(shù)據(jù),一個(gè)之前沒有緩存的數(shù)據(jù),突然大量請(qǐng)求。加鎖一個(gè)線程取數(shù)據(jù),其他線程之間返回。
總之:保證數(shù)據(jù)庫不被打垮,只讓有效請(qǐng)求進(jìn)入數(shù)據(jù)庫。加鎖只讓一個(gè)有效請(qǐng)求進(jìn)入數(shù)據(jù)庫,其他請(qǐng)求等待,如果是惡意請(qǐng)求,需要布隆過濾器,或者緩存空
5. redis如何刪除過期key
1.后臺(tái)輪詢,分段分批刪除過期key
2.請(qǐng)求的時(shí)候判斷已經(jīng)過期了
6. 緩存是如何淘汰的
lru/lfu/random/ttl
7.如何進(jìn)行緩存的預(yù)熱
提前將數(shù)據(jù)緩存到redis,如果有一些沒有緩存成功,加鎖讓一個(gè)請(qǐng)求去獲取數(shù)據(jù),其他線程等待
8. 緩存和數(shù)據(jù)庫不一致
先操作數(shù)據(jù)庫,然后刪除緩存。 如果刪除了緩存,然后另外一個(gè)操作讀取到了舊數(shù)據(jù)會(huì)導(dǎo)致數(shù)據(jù)不一致(另外一個(gè)操作可能更新數(shù)據(jù)庫前就讀取了數(shù)據(jù)庫,然后刪除緩存后才更新緩存)。這里延遲刪除一下緩存就好了。 (消費(fèi)binlog強(qiáng)制保證緩存刪除成功)
9 redis主從不一致
redis是弱一致,異步保持?jǐn)?shù)據(jù)同步。 鎖不能用主從(單實(shí)例,分片集群,redlock=》redisson)
10.redis持久化原理
RDB,AOF。 不要用作存儲(chǔ)
11. 最佳實(shí)踐
1.不要有大value,會(huì)導(dǎo)致redis單線程阻塞,拆分到多個(gè)分片上(規(guī)則用戶規(guī)則緩存是一個(gè)大key)
2.規(guī)避大數(shù)據(jù)量操作smembers,hgetall
3.避免出現(xiàn)熱點(diǎn)key,提前進(jìn)行拆分或者每個(gè)分片冗余,比如庫存。
12. redis分布式鎖
存在的問題:1.超時(shí)釋放鎖,活還沒干完。2.redis主掛了,鎖丟了。3.釋放了別人的鎖。4.沒法實(shí)現(xiàn)阻塞和公平鎖。但是redis性能高,如果用zk,鎖是靠新建和刪除臨時(shí)節(jié)點(diǎn)實(shí)現(xiàn),只有l(wèi)eader可以干,性能弱但是安全。
13. sorted set數(shù)據(jù)結(jié)構(gòu)

14.redis做延時(shí)隊(duì)列
sortedSet 用時(shí)間戳做score,消息內(nèi)容為key。 zadd添加消息,zrangebyscore獲取n秒前的數(shù)據(jù)。
2. JVM
2.1 描述一下jvm內(nèi)存模型
a. 服務(wù)啟動(dòng)的時(shí)候類加載器將class加載到方法區(qū)(持久代),持久代參數(shù)必需設(shè)置,如果不設(shè)置持久代擴(kuò)容會(huì)導(dǎo)致full gc。持久代初始值和最大值設(shè)置一樣即可。類加載相關(guān)內(nèi)容參考:http://www.itdecent.cn/p/6f18ac304255
b. 服務(wù)啟動(dòng)時(shí)創(chuàng)建的各種實(shí)例在jvm的堆中,實(shí)例的回收靠垃圾回收器,這里有cms,g1,zgc。垃圾收集器參考:http://www.itdecent.cn/p/346eb6a77da5
c. 程序運(yùn)行的時(shí)候是用的虛擬機(jī)棧,如果要調(diào)本地方法會(huì)用到本地方法棧,程序計(jì)數(shù)器指向正在執(zhí)行的指令。
2.2 堆內(nèi)存劃分的空間,如何回收這些對(duì)象
cms和g1都分新生代和老年代,新生代eden和2個(gè)survivor區(qū)。g1主要是可以控制gc時(shí)間。具體參考垃圾收集器的文章
2.3 如何解決線上頻繁gc問題
線上頻繁full gc,主要是晉升太多對(duì)象到老年的(規(guī)則的一個(gè)本地緩存每次都全量刷新,導(dǎo)致老年的增長過快),或者老年的對(duì)象泄漏了回收不了(曾遇到過打印的日志拼接在一個(gè)靜態(tài)的屬性上導(dǎo)致內(nèi)存泄漏)
2.4 常見gc問題
- young gc尖刺,因?yàn)閷懭罩居龅酱疟P繁忙
- young gc耗時(shí)緩慢增加,String.intern字符串常量池過大因?yàn)槌A砍厥莌ashtable維護(hù)的,常量池?cái)?shù)據(jù)過多hash沖突嚴(yán)重,查找就比較耗時(shí)。
- old-gen scanning時(shí)間過長,調(diào)整-XX:ParGCCardsPerStrideChunk=4096 參數(shù)
2.5 內(nèi)存溢出的原因,如何排查
outOfMemoryError:java heap space:java堆溢出,代碼問題的可能性比較大
outOfMemoryError:direct buffer memory:直接內(nèi)存不足,框架的byteBuffer分配了內(nèi)存沒有回收。
stackOverFlowError: 棧溢出
2.6 happens-before規(guī)則
程序順序規(guī)則,鎖規(guī)則,volatile變量規(guī)則,傳遞性,線程啟動(dòng)規(guī)則終止規(guī)則,線程中斷規(guī)則。
3. 多線程-面試題
1. 如何預(yù)防死鎖
按順序加鎖,批量上鎖,獲取不到鎖不阻塞,超時(shí)等待。
2.線程幾種創(chuàng)建方式
runnable
callable
繼承thread
futureTask
3.java wait和sleep的區(qū)別
wait是釋放鎖,這個(gè)鎖是打標(biāo)在對(duì)象頭,所以屬于object方法。sleep是thread的方法,因?yàn)槭蔷€程本身休眠,不釋放鎖。線程都會(huì)阻塞
4.進(jìn)程和線程的區(qū)別
進(jìn)程是系統(tǒng)資源分配的最小單位,線程是cpu調(diào)度的最小單位。 如果linux fork進(jìn)程不同享內(nèi)存,那是另外一個(gè)進(jìn)程。如果調(diào)用clone創(chuàng)建一個(gè)進(jìn)程共享同一片內(nèi)存,那叫做線程。知識(shí)換了一個(gè)名字
5.java線程生命周期
阻塞,運(yùn)行,銷毀。 新建,new一個(gè)線程,還未綁定操作系統(tǒng)的線程。 調(diào)用start后屬于就緒狀態(tài),已綁定操作線程,等待cpu調(diào)度。阻塞(等待sync鎖),等待(wait,sleep,await)
6.描述notify 和notifyAll的區(qū)別
鎖池和等待池。 調(diào)wait進(jìn)入等待池,調(diào)用notify喚醒一個(gè)進(jìn)入鎖池,調(diào)用notifyAll喚醒所有的進(jìn)入鎖池。
7.描述synchronize和lock區(qū)別
由于sync性能差,所以有l(wèi)ock。 sync只有一個(gè)等待隊(duì)列,沒有多個(gè)等待隊(duì)列。 lock是java自己實(shí)現(xiàn)的比較靈活,比如獲取鎖,和等待隊(duì)列。
8.并發(fā)和并行
并行:多個(gè)任務(wù)同時(shí)在多個(gè)cpu運(yùn)行
并發(fā):多個(gè)任務(wù)在一個(gè)cpu運(yùn)行,運(yùn)行很快看起來是一起發(fā)生
9.ABA問題
做了某一件事情,然后又恢復(fù)了,別人不知道做了這件事情。比如+1后又-1。解決方案:遞增版本號(hào)
10.實(shí)現(xiàn)一下DCL
先判空,如果為空加sync鎖,然后再判空,如果為空初始化對(duì)象。加鎖的時(shí)候,有線程進(jìn)入了競爭隊(duì)列,搶到鎖之后需要判空
11 lock condition原理

12 多個(gè)線程順序打印ABC
A線程打印A,通知B,B線程打印B通知C,C打印C。
13 volitale,atomic,lock分別解決什么問題
volitale解決可見性,atomic cas解決原子性,lock解決原子性
14 線程池運(yùn)行原理

15 synchronize原理

4. java基礎(chǔ)-面試題
面試注意點(diǎn):
熟悉的多聊(3-5分鐘),不熟悉的少聊。一個(gè)問題一個(gè)問題的環(huán)環(huán)嵌套,層層遞進(jìn),由淺入深。慢慢由自己主導(dǎo)面試,引導(dǎo)面試官問你熟悉的領(lǐng)域。
答題思路:總,分,總。 點(diǎn),線,面
1 請(qǐng)聊一下java的集合類
簡單介紹,arrayList,LinkedList,hashSet,hashMap,concurrentHashmap。
2 hashmap為什么要使用紅黑樹紅
jdk1.8 鏈表大于8變成紅黑樹,加快檢索速度。紅黑樹本身是一顆二叉樹,保證樹平衡,從而保證操作比較快。
3 集合類如何解決線程安全
ConcurrentHashMap實(shí)現(xiàn)方式,底層具體實(shí)現(xiàn),synchronized+cas保證線程安全
size方法規(guī)避偽共享,變量abc共享一個(gè)緩存行,任何一個(gè)變量修改,會(huì)導(dǎo)致abc三個(gè)變量緩存都失效叫做偽共享。
ConcurrentSkipListMap 線程安全的有序hash表(相當(dāng)于安全的treeMap),通過跳表實(shí)現(xiàn)的
copyOnWriteArrayList適合寫少讀多,寫的時(shí)候負(fù)責(zé)一個(gè)新容器,只保證最終一致性
4 簡述自定義異常場景
檢查異常統(tǒng)一處理
5 描述object常用方法
toString:對(duì)象的字符串表示形式
clone:返回一個(gè)對(duì)象的副本,深克隆,淺克隆,原型模式
finalized:GC會(huì)調(diào)用這個(gè)方法,可以使用這個(gè)方法自救
6 1.8新特性
lambda表達(dá)式
函數(shù)式接口
stream api
新時(shí)間日期api
接口默認(rèn)方法,靜態(tài)方法
7 繼承,封裝,多態(tài)
8 java重寫和重載
9 java自增是線程安全嗎,如何實(shí)現(xiàn)線程安全的自增
10 jdk1.8的stream用過嗎,stream并行原理
fork/join里面默認(rèn)線程池
11 forkjoin框架,適用場景
將大任務(wù)拆分成各個(gè)小任務(wù)。fork:分拆,join:合并
12 java 中代理有幾種模式
靜態(tài)代理
動(dòng)態(tài)代理
jdk-proxy: 面向接口的動(dòng)態(tài)代理,代理一個(gè)對(duì)象去增強(qiáng)面向某一個(gè)接口中定義的方法。缺點(diǎn):沒有接口不可用,只能讀取接口上的注解
cglib:面向父類的動(dòng)態(tài)代理,可以讀取到類上的注解
AOP:借助proxy和cglib使用
13 equal和hashcode方法要同步重寫
equal相等,hashcode一定要相等
14 hashMap在1.8做了哪些優(yōu)化
1.紅黑樹
2.鏈表插入節(jié)點(diǎn)方式:1.7頭部插入,1.8尾部插入
3.hash函數(shù):將hash值高位16位也參與hash計(jì)算,降低沖突概率
4.擴(kuò)容優(yōu)化,rehash1.8不需要重寫進(jìn)行位置計(jì)算
15hashMap為什么是擴(kuò)容2倍
1.8 擴(kuò)容之后,方便位置計(jì)算。其二,降低沖突概率
16 解決hash沖突的辦法
開放定址法,再hash法,鏈地址法
17hashmap為什么使用紅黑樹,為什么不用avl樹
18 tomcat 為什么要重寫類加載器
先講雙親委派機(jī)制,目的:實(shí)現(xiàn)隔離(一個(gè)web容器部署多個(gè)應(yīng)用,webAppClassLoader),無法實(shí)現(xiàn)熱替換,jsp修改動(dòng)態(tài)生效(jasperLoader,jsp文件有修改,廢棄jsp文件對(duì)應(yīng)的load,重新new一個(gè))。
19 java反射影響性能嗎
大量影響性能,大量本身說明編程思想有問題
20單例模式
餓漢模式
懶漢式模式
靜態(tài)內(nèi)部類
枚舉模式
5.網(wǎng)絡(luò)IO
1.網(wǎng)絡(luò)連接流程
服務(wù)端bind+listen,客戶端經(jīng)過三次握手,建立起一個(gè)連接。服務(wù)端通過accept拿到連接,如何通過accept拿連接呢,這就是io模型。boi服務(wù)端阻塞等待,nio服務(wù)端立刻返回,等待內(nèi)核回調(diào)。
2.tcp為什么是3次握手
證明雙發(fā)的收發(fā)能力,客戶端fin,證明自己??發(fā)送能力。 fin+ack,證明服務(wù)端有發(fā)送+接收能力,ack證明客戶端有接收能力
- tcp為什么是4次揮手
服務(wù)端收到客戶端斷開連接,還有事情要處理。客戶端fin標(biāo)識(shí)要斷開連接,服務(wù)端fin+ack表明收到請(qǐng)求,進(jìn)入close_wait狀態(tài)(如果很多,說明服務(wù)端忘記close)。服務(wù)端處理事情完畢后,fin客戶端收到后回復(fù)ack進(jìn)入time-wait狀態(tài)維持2msl(保證延遲的網(wǎng)絡(luò)包都消失和服務(wù)端如果沒有收到ack,會(huì)重復(fù)fin,但是客戶端關(guān)閉了,服務(wù)端會(huì)報(bào)錯(cuò)) - 長連接和短連接
長連接:復(fù)用tcp連接,缺點(diǎn):占用服務(wù)器資源,如果客戶端是固定的,而且訪問很頻繁,長連接合適
短連接:每次都需要建立連接,服務(wù)器消耗資源少。如果客戶端體量很大,一段時(shí)間是這一波用戶,一段時(shí)間是另外一撥用戶,短連接合適。
考核指標(biāo),連接建立起來,如果復(fù)用很頻繁,就長連接,反之短連接。 - epoll poll select區(qū)別
6.io模型
io分2步:1.等待網(wǎng)卡數(shù)據(jù),2.數(shù)據(jù)內(nèi)核拷貝到用戶區(qū)
BIO 同步阻塞,1,2步都阻塞
NIO 同步等待,1不阻塞(epoll),2阻塞
AIO 異步不阻塞
7.netty特點(diǎn)
傳輸快,零拷貝
高并發(fā):依賴nio
核心組件:
a. buffer: 與channel進(jìn)行交互,數(shù)據(jù)是從channel讀入緩沖區(qū),從緩沖區(qū)寫入channel中
b. flip方法:反轉(zhuǎn)緩沖區(qū),將position給limit,然后position置為0,切換讀寫模式
c. clear方法:清除此緩沖區(qū),將position置為0,吧capacity的值給limit。
d. directByteBuffer:減少系統(tǒng)空間到用戶空間的拷貝,但buffer的創(chuàng)建和銷毀成本更高,不可控,通常使用內(nèi)存池來管理。如果數(shù)據(jù)量小,中小應(yīng)用可以考慮heapBuffer,jvm來管理。
f.channel:IO源與目標(biāo)打開的連接,是雙向的,但不能直接訪問數(shù)據(jù),通過buffer交互
g. selector: 一個(gè)單獨(dú)的線程管理多個(gè)channel,open方法可創(chuàng)建selector,register方法向多路復(fù)用器注冊(cè)通道,可監(jiān)聽事件類型:讀,寫,連接,accept。
h. nio建立連接的過程:Selector.open打開一個(gè)selector,ServerSocketChannel.open()創(chuàng)建服務(wù)channel;bind():綁定到某一個(gè)端口。register()注冊(cè)channel和關(guān)注事件到selector上; select輪詢拿到已就緒事件。
i. tcp粘包,拆包原因和解決辦法
tcp以流的方式處理數(shù)據(jù),一個(gè)完整的保會(huì)被tcp拆分成多個(gè)包進(jìn)行分發(fā),也可能把消毒封裝成一個(gè)大的數(shù)據(jù)包發(fā)送。要發(fā)的數(shù)據(jù)大于包的容量發(fā)生拆包,小于的話發(fā)生粘包現(xiàn)象。
j.了解哪幾種序列號(hào)協(xié)議
關(guān)鍵因素:序列號(hào)后大小,序列號(hào)對(duì)cpu占用,是否支持跨語言
java默認(rèn)序列化:無法跨語言,序列化后大,消耗cpu
json:消耗cpu,跨語言,序列化后數(shù)據(jù)小。適合傳輸數(shù)據(jù)量少,實(shí)時(shí)性要求低的系統(tǒng)
thrift:序列化體積小,速度快,支持多語言。不適合數(shù)據(jù)持久化序列化協(xié)議,適合rpc調(diào)用
hessian 二進(jìn)制協(xié)議輕量級(jí)工具
k. reactor模型
6.mybatis
1 mybatis編程步驟
sqlSessionFactory創(chuàng)建sqlSession,通過sqlSession執(zhí)行數(shù)據(jù)庫操作,調(diào)用session.commit提交事務(wù),close關(guān)閉會(huì)話
2.mybatis工作原理
讀取mybatis配置文件,配置mybatis運(yùn)行環(huán)境比如數(shù)據(jù)庫連接信息。加載sql映射文件,文件配置了操作數(shù)據(jù)庫的sql語句。構(gòu)造會(huì)話工廠,通過環(huán)境配置信息構(gòu)建sqlSessionFactory。創(chuàng)建會(huì)話對(duì)象sqlSession。Executor執(zhí)行器,它根據(jù)sqlSession傳遞的參數(shù)動(dòng)態(tài)生成要執(zhí)行的sql語句,同時(shí)負(fù)責(zé)查詢緩存的維護(hù)。