1.在項目經歷里挑一個詳細介紹一下 項目的應用場景?
2.項目里用到多線程是怎么用的?回答:線程池?
用通過?ThreadPoolExecutor
?構造函數的方式創建的線程池
3.線程池有哪些重要參數?回答:核心線程數、最大線程數、阻塞隊列類型、拋出策略還有線程池類型。
線程池的核心線程數、最大線程數,當線程數大于核心線程數時多余的線程存活的時間,任務隊列,拒絕策略。
4.線程池類型有哪些?回答:有固定一個線程的還有按照參數指定線程數的,還有按時執行任務的。
基于ThreadPoolExecutor
共有四種類型線程池
FixedThreadPool
:固定數量線程池
SingleThreadExecutor
:單線程線程池
CachedThreadPool
:緩存線程池(是一種大小可變的線程池,線程數量根據任務的數量自動調整。)
ScheduledThreadPoolExecutor
:調度線程池(周期性地執行任務,或者在指定的時間執行任務。)
一般不建議采用Excutors類創建上述線程池,而是建議大家使用構造函數去創建線程池,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險
(1)FixedThreadPool
和 SingleThreadExecutor
:使用的是無界阻塞隊列,任務隊列最大長度為 Integer.MAX_VALUE
,可能堆積大量的請求,從而導致 OOM。
(2)CachedThreadPool
:使用的是同步隊列,允許創建的線程數量為?Integer.MAX_VALUE
?,如果任務數量過多且執行速度較慢,可能會創建大量的線程,從而導致 OOM。
(3)ScheduledThreadPool
和 SingleThreadScheduledExecutor
: 使用的無界的延遲阻塞隊列DelayedWorkQueue
,任務隊列最大長度為 Integer.MAX_VALUE
,可能堆積大量的請求,從而導致 OOM。
- 容量為
Integer.MAX_VALUE
的LinkedBlockingQueue
(無界隊列):FixedThreadPool
和SingleThreadExector
。由于隊列永遠不會被放滿,因此FixedThreadPool
最多只能創建核心線程數的線程。 SynchronousQueue
(同步隊列):CachedThreadPool
。SynchronousQueue
沒有容量,不存儲元素,目的是保證對于提交的任務,如果有空閑線程,則使用空閑線程來處理;否則新建一個線程來處理任務。也就是說,CachedThreadPool
的最大線程數是Integer.MAX_VALUE
,可以理解為線程數是可以無限擴展的,可能會創建大量線程,從而導致 OOM。DelayedWorkQueue
(延遲阻塞隊列):ScheduledThreadPool
和SingleThreadScheduledExecutor
。DelayedWorkQueue
的內部元素并不是按照放入的時間排序,而是會按照延遲的時間長短對任務進行排序,內部采用的是“堆”的數據結構,可以保證每次出隊的任務都是當前隊列中執行時間最靠前的。DelayedWorkQueue
添加元素滿了之后會自動擴容原來容量的 1/2,即永遠不會阻塞,最大擴容可達Integer.MAX_VALUE
,所以最多只能創建核心線程數的線程。
5.實際工作中參數怎么選擇呢?比如核心線程數?回答:核心線程數和cpu個數有關,一般是2n+1個
這是固定的?不是固定的,要看任務是主要使用cpu的還是占用cpu比較少的。
如果我們設置的線程池數量太小的話,如果同一時間有大量任務/請求需要處理,可能會導致大量的請求/任務在任務隊列中排隊等待執行,甚至會出現任務隊列滿了之后任務/請求無法處理的情況,或者大量任務堆積在任務隊列導致 OOM。這樣很明顯是有問題的,CPU 根本沒有得到充分利用。
如果我們設置線程數量太大,大量線程可能會同時在爭取 CPU 資源,這樣會導致大量的上下文切換,從而增加線程的執行時間,影響了整體執行效率。
假設機器有N個CPU,那么對于計算密集型的任務(壓縮、解壓縮、加密、解密、科學計算等),應該設置線程數為N+1;對于IO密集型的任務(MySQL 數據庫、文件的讀寫、網絡通信),應該設置線程數為2N;對于同時有計算工作和IO工作的任務,應該考慮使用兩個線程池,一個處理計算任務,一個處理IO任務,分別對兩個線程池按照計算密集型和IO密集型來設置線程數。
最佳線程數 = N(CPU 核心數)?(1+WT(線程等待時間)/ST(線程計算時間))
,其中?WT(線程等待時間)=線程運行總時間 - ST(線程計算時間),WT/ST可以通過VisualVM 來查看。
綜合來看,我們可以根據自己的業務場景,從“N+1”和“2N”兩個公式中選出一個適合的,計算出一個大概的線程數量,之后通過實際壓測,逐漸往“增大線程數量”和“減小線程數量”這兩個方向調整,然后觀察整體的處理時間變化,最終確定一個具體的線程數量。
6.多線程會帶來一些并發問題,一般用鎖來處理。樂觀鎖和悲觀鎖你了解嗎都是什么概念?應用于什么場景
悲觀鎖總是假設最壞的情況,認為共享資源每次被訪問的時候就會出現問題(比如共享數據被修改),所以每次在獲取資源操作的時候都會上鎖,這樣其他線程想拿到這個資源就會阻塞直到鎖被上一個持有者釋放。也就是說,共享資源每次只給一個線程使用,其它線程阻塞,用完后再把資源轉讓給其它線程。常見的悲觀鎖有java的synchronized、ReentrantLock
等獨占鎖。悲觀鎖通常用于寫比較多的情況,可以避免頻繁失敗和重試影響性能,開銷是固定的。
樂觀鎖總是假設最好的情況,認為共享資源每次被訪問的時候不會出現問題,線程可以不停地執行,無需加鎖也無需等待,只是在提交修改的時候去驗證對應的資源(也就是數據)是否被其它線程修改了(具體方法可以使用版本號機制或 CAS 算法)。JUC包下的原子變量類,比如AtomicInteger、LongAdder就是使用了樂觀鎖的一種實現方式CAS實現的。樂觀鎖通常用于寫比較少的情況,比如多讀場景,競爭比較少,可以避免頻繁加鎖影響性能。不過樂觀鎖主要針對的對象是單個共享變量。
從 JDK 1.5 開始,提供了AtomicReference
類來保證引用對象之間的原子性,你可以把多個變量放在一個對象里來進行 CAS 操作.所以我們可以使用鎖或者利用AtomicReference
類把多個共享變量合并成一個共享變量來操作。
7.你用過的鎖有哪些,sychronized鎖升級的流程
8.看你的簡歷有一個oom的排查和一個循環依賴的排查,能詳細講講嗎(這里講的不好,再深入一下)
日志顯示OOM,是一個堆內存的泄漏 OutOfMemoryError: Java heap space
查看dump文件,默認存儲在啟動該jar的用戶根目錄下,用MemoryAnalyzer對dump文件進行分析,發現占用內存異常的是一個map,定位到DistributedFileSystem,以此為關鍵字在項目里排查。
定位到代碼中發現是之前為解決“兩個HDFS集群namespace同名時會造成兩個集群讀取到同一套文件系統”的問題,由調用get(hadoopConfig)方法換為調用newInstance方法新建實例。但是該方法中會一直往一個靜態的cache的map里放值,在定時多次調用的情況下,map一直不會被回收但是內部一直在添加新值造成OOM。后續解決方法是將FileSystem保存到map緩存里,FileSystem是通過集群名和集群配置生成的,如果map緩存中存在該實例就從緩存中讀取,不存在才新增。
FileSystem是根據集群名和配置生成的,之前的get方法只用配置拿,因此同名的集群區分不了。
9.你項目哪里用到了redis 怎么用的(這里因為沒問過也沒深入下去,接下來把redis加入到項目里)
10.項目主要用mysql,處理過海量數據嗎 有哪些優化手段?一般對哪些字段建索引,索引的個數為什么不是越多越好?
哪些情況需要創建索引:(1)主鍵會自動建立唯一索引 (2)頻繁作為查詢條件的字段需要建立索引,在where語句用到的字段加索引 (3)查詢與其他表關聯的字段,會在on的外鍵關系上建立索引 (4)多字段查詢可以創建組合索引 (5)有序字段適合創建索引 (6)查詢中統計或者分組字段(有區分度的字段,可能會拿來做分組的字段)
不適合加索引的地方:(1)頻繁更新的字段不適合創建索引。更新字段的過程中,需要維護B+樹結構,會頻繁更新索引文件,降低SQL性能。(2)過長的字段不適合創建索引。(占用空間多)(3)無序的字段不適合創建索引。
優先使用聯合索引,聯合索引時將高區分度的字段放到前面。
創建過多的索引,會占用更多存儲空間,另外也會嚴重影響SQL性能,每次更刪改查SQL都需要更新大量索引文件。
11.看簡歷寫到過設計模式,你熟悉哪些設計模式? 回答了建造者、簡單工廠。
了解代理模式嗎?哪里用過代理模式
12.hashmap結構
13.怎么判斷能獲取到的mysql鎖是表級鎖還是行級鎖?
14.平時使用update select這些語句什么情況下會上鎖,會上哪種鎖
一些非技術相關提問:
1.過去開發時候 產品 測試 前端這些都有吧 介紹一下大概多少人 都有哪些角色參與生產
提問:組里的人員構成和架構?組里主要做什么 信貸平臺的底層平臺 做一些支付或者用戶權限的認證 十個人 每兩三個一組。初中高級比例大概怎么樣?一比一
2.如果已經開發要完成了,產品提出加需求怎么辦
3.今天面試我很多地方深入的了解都不夠,你比較看中求職者哪些方面技術能力。比如redis這種我沒有實際沒有應用的,但是自己也看了一下,但沒有實際經驗面試官也不接著問下去了,比如這種知識我怎么準備呢
這還是每個面試官有不同的側重點,從我的角度我更看重對你用過的技術的考察,如果工作三到四年沒用過redis就不正常,但是你經驗一年可以理解,但是目前大多數面試的十個人里面只有一兩個沒用過,所以還是建議多一些實際使用的經驗。
總結:
1.多線程、mysql調優這些用過的但是不深入的東西需要重點學習!
2.redis看完基礎教程以后加入到項目里,不要讓他成為短板。
3.OOM和循環依賴那個的介紹要再熟悉深入一下。
4.leetcode還是要繼續刷。