(一)Java基礎
1、線程池的原理
預先啓動一些線程,線程無限循環從任務隊列中獲取一個任務進行執行,直到線程池被關閉。如果某個線程因爲執行某個任務發生異常而終止,那麼重新創建一個新的線程而已。如此反覆。
2、爲什麼要創建線程池?
線程池爲線程生命週期開銷問題和資源不足問題提供瞭解決方案。
(1)通過對多個任務重用線程,線程創建的開銷被分攤到了多個任務上。其好處是,因爲在請求到達時線程已經存在,所以無意中也消除了線程創建所帶來的延遲。這樣,就可以立即爲請求服務,使應用程序響應更快。
(2)而且,通過適當地調整線程池中的線程數目,也就是當請求的數目超過某個閾值時,就強制其它任何新到的請求一直等待,直到獲得一個線程來處理爲止,從而可以防止資源不足。
3、線程的生命週期
(1)新建 New
當創建Thread類的一個實例(對象)時,此線程進入新建狀態(未被啓動)。例如:Thread t1=new Thread();
(2)就緒 Runnable
調用Thread類的start方法,線程已經被啓動,進入就緒狀態,正在等待被分配給CPU時間片,也就是說此時線程正在就緒隊列中排隊等候得到CPU資源。
(3)運行 Running
線程獲得CPU資源正在執行任務(執行run()方法),此時除非此線程自動放棄CPU資源或者有優先級更高的線程進入,線程將一直運行到結束或者時間片結束。
(4)阻塞 Blocked
由於某種原因導致正在運行的線程讓出CPU並暫停自己的執行,即進入堵塞狀態。阻塞結束後線程進入就緒狀態。
堵塞的情況分三種:
(一)等待堵塞:執行的線程執行wait()方法,JVM會把該線程放入等待池中。
(二)同步堵塞:執行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用。則JVM會把該線程放入鎖池中。
(三)其它堵塞:執行的線程執行sleep()或join()方法,或者發出了I/O請求時。JVM會把該線程置爲堵塞狀態。
當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完成時。線程又一次轉入就緒狀態。
(5)死亡 Dead
當線程執行完畢(run方法運行結束)或被其它線程殺死,線程就進入死亡狀態,這時線程不可能再進入就緒狀態等待執行。
4、什麼是線程安全,如何實現線程安全?
(1)當多個線程訪問某個方法時,不管你通過怎樣的調用方式或者說這些線程如何交替的執行,我們在主程序中不需要去做任何的同步,這個類的結果行爲都是我們設想的正確行爲,那麼我們就可以說這個類時線程安全的。
(2)一般來說,基本上所有的併發模式在解決線程安全問題時,採用的操作都是序列化訪問共享資源。在java中,提供了兩種方式,synchronized和Lock。
9、wait()與 sleep()的區別?
sleep()來自 Thread 類,wait()來自 Object 類;
調用 sleep()方法,線程不會釋放對象鎖。而調用 wait 方法線程會釋放對象鎖;
sleep()睡眠後不出讓系統資源,wait 讓其他線程可以佔用 CPU;
sleep(milliseconds)需要指定一個睡眠時間,時間一到會自動喚醒。而 wait()需要配合 notify()
或者 notifyAll()使用。
5、synchronized、volatile區別
- volatile本質是在告訴jvm當前變量在寄存器(工作內存)中的值是不確定的,需要從主存中讀取; synchronized則是鎖定當前變量,只有當前線程可以訪問該變量,其他線程被阻塞住。
- volatile僅能使用在變量級別;synchronized則可以使用在變量、方法、和類級別的
- volatile僅能實現變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性
- volatile不會造成線程的阻塞;synchronized可能會造成線程的阻塞。
- volatile標記的變量不會被編譯器優化;synchronized標記的變量可以被編譯器優化
6、Java9比Java8改進了什麼;
modularity System 模塊系統、HTTP/2、JShell、不可變集合工廠方法、私有接口方法、HTML5風格的Java幫助文檔、多版本兼容 JAR、統一 JVM 日誌、I/O 流新特性
7、HashMap內部的數據結構是什麼?底層是怎麼實現的?
8、說說反射的用途及實現,反射是不是很慢,我們在項目中是否要避免使用反射;
9、說說自定義註解的場景及實現;
10、List和Map區別,Arraylist與LinkedList區別,ArrayList與Vector 區別;
(1)List,Set都是繼承自Collection接口,Map則不是
(2)ArrayList和LinkedList的大致區別如下:
- ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
- 對於隨機訪問get和set,ArrayList覺得優於LinkedList,因爲LinkedList要移動指針。
- 對於新增和刪除操作add和remove,LinedList比較佔優勢,因爲ArrayList要移動數據。
(3)ArrayList與Vector 區別:
- Vector的方法都是同步的(Synchronized),是線程安全的(thread-safe),而ArrayList的方法不是,由於線程的同步必然要影響性能,因此,ArrayList的性能比Vector好。
- 當Vector或ArrayList中的元素超過它的初始大小時,Vector會將它的容量翻倍,而ArrayList只增加50%的大小,這樣,ArrayList就有利於節約內存空間。
(二)JVM相關
1、JVM內存模型,GC機制和原理;GC分哪兩種;什麼時候會觸發Full GC?
2、JVM裏的有幾種classloader,爲什麼會有多種?
3、什麼是雙親委派機制?介紹一些運作過程,雙親委派模型的好處;(這個我真的不會…)
4、什麼情況下我們需要破壞雙親委派模型;
5、常見的JVM調優方法有哪些?可以具體到調整哪個參數,調成什麼值?
6、JVM虛擬機內存劃分、類加載器、垃圾收集算法、垃圾收集器、class文件結構是如何解析的;
(三)Java多線程
1、什麼是 ThreadLocal?ThreadLocal 和 Synchonized 的區別?
線程局部變量。是侷限於線程內部的變量,屬於線程自身所有,不在多個線程間共享。Java提供 ThreadLocal 類來支持線程局部變量,是一種實現線程安全的方式。
synchronized 是利用鎖的機制,使變量或代碼塊在某一時該只能被一個線程訪問。而 ThreadLocal 爲每一個線程都提供了變量的副本,使得每個線程在某一時間訪問到的並不是同一個對象,這樣就隔離了多個線程對數據的數據共享。
2、創建線程的方式?
繼承 Thread 類、實現 Runnable 接口、使用 Executor 框架
(四)Spring專欄
1、Spring AOP的實現原理和場景;(應用場景很重要)
實現AOP的技術,主要分爲兩大類:一是採用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行爲的執行;二是採用靜態織入的方式,引入特定的語法創建“方面”,從而使得編譯器可以在編譯期間織入有關“方面”的代碼。
具體可以在下面的場景中使用:
- Authentication 權限
- Caching 緩存
- Context passing 內容傳遞
- Error handling 錯誤處理
- Lazy loading 懶加載
- Debugging 調試
- logging, tracing, profiling and monitoring 記錄 跟蹤 優化 校準
- Performance optimization 性能優化
- Persistence 持久化
- Resource pooling 資源池
- Synchronization 同步
- Transactions 事務
2、Spring bean的作用域和生命週期
SpringBean的作用域
- scope:設置bean的作用範圍
- singleton:單例(創建只有一個實例)
- prototype:原型(創建多個實例)
- request:對request請求創建新的bean
- session:一次會話中創建同一個bean
- global-session:所有會話共享一個bean
Bean實例生命週期的執行過程如下:
- Spring對bean進行實例化,默認bean是單例;
- Spring對bean進行依賴注入;
- 如果bean實現了BeanNameAware接口,spring將bean的id傳給setBeanName()方法;
- 如果bean實現了BeanFactoryAware接口,spring將調用setBeanFactory方法,將BeanFactory實例傳進來;
- 如果bean實現了ApplicationContextAware接口,它的setApplicationContext()方法將被調用,將應用上下文的引用傳入到bean中;
- 如果bean實現了BeanPostProcessor接口,它的postProcessBeforeInitialization方法將被調用;
- 如果bean實現了InitializingBean接口,spring將調用它的afterPropertiesSet接口方法,類似的如果bean使用了init-method屬性聲明瞭初始化方法,該方法也會被調用;
- 如果bean實現了BeanPostProcessor接口,它的postProcessAfterInitialization接口方法將被調用;
- 此時bean已經準備就緒,可以被應用程序使用了,他們將一直駐留在應用上下文中,直到該應用上下文被銷燬;
- 若bean實現了DisposableBean接口,spring將調用它的distroy()接口方法。同樣的,如果bean使用了destroy-method屬性聲明瞭銷燬方法,則該方法被調用;
3、Spring Boot比Spring做了哪些改進?
Spring Boot 基本上是 Spring 框架的擴展,它消除了設置 Spring 應用程序所需的 XML配置,爲更快,更高效的開發生態系統鋪平了道路。以下是 Spring Boot 中的一些特點:
- 創建獨立的 spring 應用。
- 嵌入 Tomcat , Jetty Undertow 而且不需要部署他們。
- 提供的“starters” poms來簡化 Maven 配置
- 儘可能自動配置 spring 應用。
- 提供生產指標,健壯檢查和外部化配置
- 絕對沒有代碼生成和 XML 配置要求
4、Spring IOC是什麼?優點是什麼?
5、SpringMVC、動態代理、反射、AOP原理、事務隔離級別;
(五)Java框架技術
(六)中間件
1、瞭解幾種消息中間件產品?各產品的優缺點介紹;
2、消息中間件如何保證消息的一致性和如何進行消息的重試機制(冪等性)?
產生消息的業務動作和消息發送的一致: 如果業務動作執行成功了,那麼這個動作產生的消息一定要發送出去。另一方面,如果這個業務沒有發生或者失敗,就不應該把消息發送出去。
3、怎麼避免消息隊列中的消息丟失和消息重複?
消息重複:
(1)在發送端和消費端都建立消息記錄表,當發送端操作成功後,在發送端的消息記錄表中建立一條記錄,狀態標識成uncomfirm(未確認),將消息投遞到消息隊列
(2)消費端從消息隊列中獲取消息後,根據消息操作成功後,在消費端的記錄表中建立一條記錄,狀態標識爲confirmed
在支付寶端和餘額寶端同時建立消息表
(3)消費端將響應消息投遞到響應隊列, 發送端獲得響應後, 查詢發送端的消息表, 如果其中沒有消費記錄, 則插入新的消息。如果查詢有消費的消息, 就停止插入, 並返回已經消費的消息。這樣可以避免消息重複消費的問題。
(4)發送端端會有一個定時任務, 相隔一段時間就從消息表中將unconfirm的消息拉取並重新發送, 這樣可以避免消息丟失的問題
4、RabbitMQ 工作模式
簡單模式:一個生產者發送消息到隊列,一個消費者接收。
工作隊列模式:一個生產者,多個消費者,每個消費者獲取到的消息唯一,多個消費者只有一個隊列。
發佈/訂閱模式:一個生產者發送的消息會被多個消費者獲取,每個消費者只能從自己訂閱的隊列中獲取。
路由模式:生產者發佈消息的時候添加路由鍵,消費者綁定隊列到交換機時添加鍵值,這樣就可以接收到需要接收的消息。
通配符模式:基本思想和路由模式是一樣的,只不過路由鍵支持模糊匹配,符號“#”匹配一個或多個詞,符號“*”只匹配一個詞。
(七)關係型數據庫
1、鎖機制介紹:行鎖、表鎖、排他鎖、共享鎖;
2、樂觀鎖的業務場景及實現方式;
3、事務介紹,分佈式事物的理解,常見的解決方案有哪些,什麼事兩階段提交、三階段提交;
4、MySQL記錄binlog的方式主要包括三種模式?每種模式的優缺點是什麼?
5、MySQL鎖,悲觀鎖、樂觀鎖、排它鎖、共享鎖、表級鎖、行級鎖;
6、分佈式事務的原理2階段提交,同步異步阻塞非阻塞;
7、數據庫事務隔離級別,MySQL默認的隔離級別、Spring如何實現事務、
8、JDBC如何實現事務、嵌套事務實現、分佈式事務實現;
9、SQL的整個解析、執行過程原理、SQL行轉列;
(八)非關係型數據庫
1、Redis爲什麼這麼快?redis採用多線程會有哪些問題?
2、Redis支持哪幾種數據結構;
3、Redis跳躍表的問題;
4、Redis單進程單線程的Redis如何能夠高併發?
5、Redis如何使用Redis實現分佈式鎖?
6、Redis分佈式鎖操作的原子性,Redis內部是如何實現的?
(九)分佈式和微服務
1、Dubbo完整的一次調用鏈路介紹;
2、Dubbo支持幾種負載均衡策略?
3、Dubbo Provider服務提供者要控制執行併發請求上限,具體怎麼做?
4、Dubbo啓動的時候支持幾種配置方式?
5、瞭解幾種消息中間件產品?各產品的優缺點介紹;
6、消息中間件如何保證消息的一致性和如何進行消息的重試機制?
7、Spring Cloud熔斷機制介紹;
8、Spring Cloud對比下Dubbo,什麼場景下該使用Spring Cloud?
(十)拓展或算法
1、紅黑樹的實現原理和應用場景;
2、NIO是什麼?適用於何種場景?