这里有一份面筋请查收(七)
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
歡迎跳轉到本文的原文鏈接:https://honeypps.com/talk/interview-7/
本篇所要介紹的是一家互聯網企業,簡稱MD好了。一面是電面,二三面是face2face的技術面,4面是HR面。
###一面
一面的具體內容忘了記錄了,大概面了45mins,問了30mins的NIO。
這里就來講一講NIO的一些知識點。NIO有三個部分:Selector, Channel和Buffer. 傳統的IO基于字節流和字符流進行操作。而NIO基于Channel和Buffer(緩沖區)進行操作,數據總是從通道讀取到緩沖區,或者從緩沖區寫入通道中。Selector用于監聽多個通道的時間(比如打開,數據到達),因此,單個線程可以監聽多個數據通道。
Selector內部原理實際是在做一個對所注冊的Channel的輪詢訪問,不斷的輪詢,一旦輪詢到一個channel有所注冊的事情發生,比如數據來了,他就會站起來報告,交出一把鑰匙(SelectionKey),讓我媽通過這把鑰匙來讀取channel的內容。
NIO有一個重要的點是:Reactor模式。從網上摳來一張Reactor模式的模型圖如下:
Reactor模式有兩大角色:Reactor和Handler. Reactor負責響應I/O事件;Handler負責非阻塞行為。至于Reactor模式的編碼風格我就不贅述了。
前面說到了Selector的原理就是輪詢,但是Java NIO中有個epoll()(linux系統下),這個對并發idle Connection會有大幅度的性能提升。epoll是linux下多路復用I/O接口Select/poll的增強版本。一般的輪詢方式一個進程打開的FD(File Descriptor)是有一定限制的,FD_SETSIZE默認是2048,這個宏定義可以修改,但修改后的效果并不理想,對于那些需要支持上萬連接數的IM服務器來說顯然太少。epoll沒有這個限制,可以通過"cat /proc/sys/fs/file-max"來查看支持的FD上限。博主本地機器是205822。epoll()有兩種使用模式:LT(Level triggered)缺省,ET(Edge-triggered)高速。
epoll有一個著名的epoll-bug, 也可能會導致無效的狀態的選擇和100%的CPU利用率,要解決epoll-bug的唯一方法是回收舊的選擇,將先前注冊的通道實例轉移到新創建的選擇器上。當然如果使用一些框架比如:Netty, Mina.
上面的全問到了,問的還挺深的。最后問了為什么沒用Netty之類的框架實現,還有有了解過其他的分布式框架么?
還問了一些Java基礎題。
比如多線程的ThreadPollExecutor中的飽和策略有哪些?
Ans:當線程池和隊列都滿了,則表明該線程池已達飽和狀態。
- ThreadPoolExecutor.AbortPolicy:處理程序遭到拒絕,則直接拋出運行時異常 RejectedExecutionException。(默認策略)
- ThreadPoolExecutor.CallerRunsPolicy:調用者所在線程來運行該任務,此策略提供簡單的反饋控制機制,能夠減緩新任務的提交速度。
- ThreadPoolExecutor.DiscardPolicy:無法執行的任務將被刪除。
- ThreadPoolExecutor.DiscardOldestPolicy:如果執行程序尚未關閉,則位于工作隊列頭部的任務將被刪除,然后重新嘗試執行任務(如果再次失敗,則重復此過程)。
線程池怎么合理配置?
Ans:需要針對具體情況而具體處理,不同的任務類別應采用不同規模的線程池,任務類別可劃分為CPU密集型任務、IO密集型任務和混合型任務。
- 對于CPU密集型任務:線程池中線程個數應盡量少,不應大于CPU核心數;
- 對于IO密集型任務:由于IO操作速度遠低于CPU速度,那么在運行這類任務時,CPU絕大多數時間處于空閑狀態,那么線程池可以配置盡量多些的線程,以提高CPU利用率;
- 對于混合型任務:可以拆分為CPU密集型任務和IO密集型任務,當這兩類任務執行時間相差無幾時,通過拆分再執行的吞吐率高于串行執行的吞吐率,但若這兩類任務執行時間有數據級的差距,那么沒有拆分的意義。
線程數的個數?(這個問題二面也問到了)
Nthreads = NcpuUcpu(1+W/C)。Ncpu是cpu的個數,可以通過Runtime.getRuntime.availableProcessors()獲取。Ucpu是cpu的使用率。W/C=Wait-Time/Compute-Time. ps:Runtime.getRuntime是單例模式。
###二面
二面先對簡歷上的內容詢問了一番,問了一些問題,再此就不表了,接下去問了些Java類的問題。
1.線程池ThreadPoolExecutor以及Executors的一些問題。
2.ReentrantLock和synchronized的區別。
- ReentrantLock可以中斷地獲取鎖(void lockInterruptibly() throws InterruptedException)
- ReentrantLock可以嘗試非阻塞地獲取鎖(boolean tryLock())
- ReentrantLock可以超時獲取鎖。通過tryLock(timeout, unit),可以嘗試獲得鎖,并且指定等待的時間。
- ReentrantLock可以實現公平鎖。通過new ReentrantLock(true)實現。
- ReentrantLock對象可以同時綁定多個Condition對象,而在synchronized中,鎖對象的的wait(), notify(), notifyAll()方法可以實現一個隱含條件,如果要和多于一個的條件關聯的對象,就不得不額外地添加一個鎖,而ReentrantLock則無需這樣做,只需要多次調用newCondition()方法即可。
從上面的比較中可以看出ReentrantLock比synchronized有很多的優點,但是JDK的開發團隊還是推崇使用synchronized的方式,在JDK5中ReentrantLock比synchronized的性能優越很多,在JDK6中進行了很多的優化,ReentrantLock比synchronized只是稍微好點,而且ReentrantLock用的不好,比如Lock.lock之后再finally塊中忘了Lock.unlock操作鎖就永遠得不到釋放,而synchronized可以自動釋放鎖。而且經過JDK的開發團隊的不懈努力,synchronized的性能會越來越好,比如:偏向鎖,輕量級鎖,自旋鎖,鎖粗化以及鎖細化等優化操作。
3.ReentrantLock又稱之為什么?怎么實現的?還有那些相同的?
ReentrantLock又稱之為可重入鎖,內部實現是基于AQS的(對于AQS不明白的小伙伴可以度娘了)。還有一些也是基于AQS的比如Semaphore,還有ReentrantReadWriteLock(獨占鎖+共享鎖)。在ReentrantReadWriteLock中又涉及了一個鎖降級的概念:先Hold寫鎖,再獲取讀鎖,再釋放寫鎖。沒有鎖升級的概念。(有關多線程的知識,可以翻看博主相關的文章,詳情見參考資料1-4。)
4.sleep和wait的區別?為什么sleep在Thread中,wait在Object中?
sleep不讓出鎖,它不會導致鎖行為的改變,而wait會讓出鎖。Thread.sleep的調用不會影響鎖的改變,所以放在sleep中,wait與鎖有關所以放在Object中。
5.為什么Java中的鎖是對象鎖而不是線程鎖?
這個問題比較抽象,主要是在對象鎖的編程模型比較簡單,線程鎖其實也可以,但是編程模型太復雜,所以Java采用的對象鎖。
6. 寫一個單例模式。
博主寫了一個內部類的單例模式,然后說了其他的寫法比如:enum或者synchronized的寫法,詳情可以關注《設計模式:單例模式(Singleton)》。
后面又問了一個問題:一個類中所有的方法和屬性都標注為static的,那么這是一個單例么?面試官的語氣暗示這不是一個單例,但的確想不出不是單例的地方,想了一會兒才明白過來這的確是一個單例的寫法。單例是保證一個類的實例構造器只實現一次,而全部標注為static的類,它就只有類構造器,類構造器可以由JVM確保只執行一次,而且是線程安全的。
還有一道設計題:微信公眾號拉取粉絲數量。
###三面
三面的面試官照著簡歷問了一些問題,然后問了一些其他的和技術無關的,最后還問了一個技術類問題:怎么可以發生Full GC?
Full GC是指老年代發生了Stop the world的操作。詳細可以參考《Java堆內存 》。
比如在CMS執行時有初始標記、并發標記、重新標記、并發清除、并發重置5個步驟中,初始標記和重新標記都是stop the world的,當發生Concurrent Mode Failure時,會觸發一次Serial-Old的操作。
可以在程序中通過設置-Xmx, -Xms等參數去觸發,也可以通過System.gc()觸發。當然有兩個工具JConsole和JVsualVm中有“GC”的按鈕。
(剩下的可以在留言區補充。)
總結:無。(對這家公司太熟悉,不方便評價~~)
更多鏈接請關注:
這里有一份面筋請查收(一)
這里有一份面筋請查收(二)
這里有一份面筋請查收(三)
這里有一份面筋請查收(四)
這里有一份面筋請查收(五)
這里有一份面筋請查收(六)
這里有一份面筋請查收(七)
這里有一份面筋請查收(八)
參考資料
歡迎跳轉到本文的原文鏈接:https://honeypps.com/talk/interview-7/
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
總結
以上是生活随笔為你收集整理的这里有一份面筋请查收(七)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 这里有一份面筋请查收(六)
- 下一篇: 这里有一份面筋请查收(八)