網際網路大廠java面試題-阿里

碼農彬哥 發佈 2022-02-06T20:43:39+00:00

在事務正確提交之前,不允許把該事務對數據的任何改變提供給任何其他事務。事務正確提交後,其結果將永久保存在資料庫中,即使在事務提交後有了其他故。

1、TCP 和 UDP 區別?

TCP 基於連接,UDP 基於無連接。

TCP 要求系統資源較多,UDP 較少。

UDP 程序結構較簡單。

TCP 保證數據正確性,UDP 可能丟包。

TCP 保證數據順序,UDP 不保證。

2、TCP/IP 協議涉及哪幾層架構?

應用層 傳輸層 互連網絡層 網絡接口層。

3、描述下 TCP 連接 4 次揮手的過程?為什麼要 4 次揮手?

因為 TCP 是全雙工,每個方向都必須進行單獨關閉。關閉連接時,當 Server 端收到 FIN

報文時,很可能並不會立即關閉 SOCKET,所以只能先回復一個 ACK 報文,告訴 Client

端,」你發的 FIN 報文我收到了」。只有等到 Server 端所有的報文都發送完了,我才能發

送 FIN 報文,因此不能一起發送。故需要四步握手。

4、計算機插上電源作業系統做了什麼?

加電––––打開電源開關,給主板和內部風扇供電。

啟動引導程序––––CPU 開始執行存儲在 ROM BIOS 中的指令。

開機自檢––––計算機對系統的主要部件進行診斷測試。

加載作業系統––––計算機將作業系統文件從磁碟讀到內存中。

檢查配置文件,定製作業系統的運行環境––––讀取配置文件,根據用戶的設置對操作

系統進行定製。

準備讀取命令和數據––––計算機等待用戶輸入命令和數據。

5、Linux 作業系統設備文件有哪些?

字符設備、塊設備。

6、多線程同步有哪些方法?

使用 synchronized 關鍵字

wait 和 notify

使用特殊域變量 volatile 實現線程同步

使用重入鎖實現線程同步

使用局部變量來實現線程同步

使用阻塞隊列實現線程同步

使用原子變量實現線程同步

7、一個對象的兩個方法加 synchronized,一個線程進去 sleep,另一個線程可以進入到另一個方法嗎?

不能。

8、什麼是可重入鎖(ReentrantLock)?

舉例來說明鎖的可重入性

public class UnReentrant{
lock lock = new Lock();
public void outer(){
lock.lock();
inner();
lock.unlock();
}
public void inner(){
lock.lock();
//do something
lock.unlock();
}
}

outer 中調用了 inner,outer 先鎖住了 lock,這樣 inner 就不能再獲取 lock。其實調用

outer 的線程已經獲取了 lock 鎖,但是不能在 inner 中重複利用已經獲取的鎖資源,這種

鎖即稱之為不可重入可重入就意味著:線程可以進入任何一個它已經擁有的鎖所同步著的代碼塊。

synchronized、ReentrantLock 都是可重入的鎖,可重入鎖相對來說簡化了並發編程的開發。

9、創建線程的三個方法是什麼?

通過繼承 Thread 類創建線程類。

實現 Runnable 接口創建線程類。

通過 Callable 和 Future 接口創建線程。

10、java 怎麼獲取多線程的返回值?

主線程等待。

使用 Thread 的 join 阻塞當前線程等待。

實現 Callable 接口(通過 FutureTask 或線程池的 Future)。

11、線程池有哪幾種創建方式?

Java 通過 Executors(jdk1.5 並發包)提供四種線程池,分別為:

newCachedThreadPoo創建一個可緩存線程池,如果線程池長度超過處理需要,可靈

活回收空閒線程,若無可回收,則新建線程。

newFixedThreadPoo創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊

列中等待。

newScheduledThreadPoo創建一個定長線程池,支持定時及周期性任務執行。

newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執

行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

12、線程池參數有哪些?

corePoolSize 核心線程大小。

maximumPoolSize 線程池最大線程數量。

keepAliveTime 空閒線程存活時間。

unit 空間線程存活時間單位。

workQueue 工作隊列。

threadFactory 線程工廠。

handler 拒絕策略。

13、線程池拒絕策略有哪些?

ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出 RejectedExecutionException 異常

(默認拒絕策略)。

ThreadPoolExecutor.DiscardPolicy:丟棄任務,但是不拋出異常。

ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然後重新提交被

拒絕的任務。

ThreadPoolExecutor.CallerRunsPolicy:由調用線程(提交任務的線程)處理該任務。

14、你認為對線程池的核心參數實現自定義可配置,三個核心參數是?

corePoolSize : 核心線程數線程數定義了最小可以同時運行的線程數量。

maximumPoolSize : 當隊列中存放的任務達到隊列容量的時候,當前可以同時運行的線

程數量變為最大線程數。

workQueue: 當新任務來的時候會先判斷當前運行的線程數量是否達到核心線程數,如果

達到的話,信任就會被存放在隊列中。

15、ThreadPoolExecutor 線程池,corePoolSize=5, maximumPoolSize=10,queueCapacity=10,有 20 個耗時任務 交給這個 線程池執行,線程池會如何執行這 20 個任務?

如果當前線程數<corePoolSize,如果是則創建新的線程執行該任務 。

如果當前線程數>=corePoolSize,則將任務存入 BlockingQueue 。

如果阻塞隊列已滿,且當前線程數<maximumPoolSize,則新建線程執行該任務。

如果阻塞隊列已滿,且當前線程數>=maximumPoolSize,則拋出異常 RejectedExecutionException,告訴調用者無法再接受任務了。

16、給用戶發消息任務超出隊列,你用哪個拒絕策略?有其他方法嗎 ?

ThreadPoolExecutor.CallerRunsPolicy

無界隊列(LinkedBlockingQuene),繼續添加任務到阻塞隊列中等待執行。

用消息隊列存任務數據,線程池慢慢處理。

17、Java8 新特性有哪些了解?

接口的默認方法

lambda 表達式

函數式接口

方法和構造函數引用

Lamda 表達式作用域

內置函數式接口

Optional

Streams(流)

ParalleStreams(並行流)

Maps

Date API(日期相關 API)

Annotations(註解)

18、什麼時候用多線程、為什麼要設計多線程?

高並發

系統接受實現多用戶多請求的高並發時,通過多線程來實現。

線程後台處理大任務

一個程序是線性執行的。如果程序執行到要花大量時間處理的任務時,那主程序就得等待其執

行完才能繼續執行下面的。那用戶就不得不等待它執行完。

這時候可以開線程把花大量時間處理的任務放在線程處理,這樣線程在後台處理時,主程序也

可以繼續執行下去,用戶就不需要等待。線程執行完後執行回調函數。

大任務

大任務處理起來比較耗時,這時候可以起到多個線程並行加快處理(例如:分片上傳)。

好處:可以提高 CPU 的利用率。在多線程程序中,一個線程必須等待的時候,CPU 可以運

行其他的線程而不是等待,這樣就大大提高了程序的效率。也就是說允許單個程序創建多個並行執行的線程來完成各自的任務。

19、多線程越多效率越高嗎?

不是

當線程總數較少時,線程越多,效率越高。

當線程總數較多時,由於線程本身調用耗時,線程越多,效率越低。

線程數越多會造成線程的生命周期開銷非常高消耗過多的 CPU 資源。

20、多線程會產生哪些並發問題 ?

安全性問題:在單線程系統上正常運行的代碼,在多線程環境中可能會出現意料之外的結果。

活躍性問題:不正確的加鎖、解鎖方式可能會導致死鎖 or 活鎖問題。

性能問題:多線程並發即多個線程切換運行,線程切換會有一定的消耗並且不正確的加鎖。

21、Mybatis 如何將對象轉換成 SQL?

sql綁定是在加載 Mybatis 配置文件,然後掃描到哪個 mapper 子節點,再加載

mapper 映射文件,掃描裡面的 SQL節點,然後封裝成對象(MappedStatement,在這個

對象的 SqlSource 封裝著 sql語句)。所有的配置信息保存在 Configuration 類,最後動

態代理執行的時候,取出來封裝 sql的對象,執行 sql。

22、虛擬內存是什麼,虛擬內存的原理是什麼?

虛擬內存是計算機系統內存管理的一種技術。

虛擬內存有以下兩個優點:

虛擬內存地址空間是連續的,沒有碎片。

虛擬內存的最大空間就是 cup 的最大尋址空間,不受內存大小的限制,能提供比內存更

大的地址空間。

當每個進程創建的時候,內核會為每個進程分配虛擬內存,這個時候數據和代碼還在磁碟上,當運行到對應的程序時,進程去尋找頁表,如果發現頁表中地址沒有存放在物理內存上,而是在磁碟上,於是發生缺頁異常,於是將磁碟上的數據拷貝到物理內存中並更新頁表,下次再訪問該虛擬地址時就能命中了。

23、棧會溢出嗎?什麼時候溢出?方法區會溢出嗎?

棧是線程私有的,它的生命周期與線程相同,每個方法在執行的時候都會創建一個棧幀,用來存儲局部變量表,操作數棧,動態連結,方法出口等信息。局部變量表又包含基本數據類型,對象引用類型。如果線程請求的棧深度大於虛擬機所允許的最大深度,將拋出

StackOverflowError 異常,方法遞歸調用產生這種結果。如果 Java 虛擬機棧可以動態擴展,並且擴展的動作已經嘗試過,但是無法申請到足夠的內存去完成擴展,或者在新建立線程的時候沒有足夠的內存去創建對應的虛擬機棧,那麼 Java 虛擬機將拋出一個 OutOfMemory 異常。(線程啟動過多)。方法區會發生溢出。

HotSpot jdk1.7 之前字符串常量池是方法區的一部分,方法區叫做「永久代」,在 1.7 之

前無限的創建對象就會造成內存溢出,提示信息:PermGen space 而是用 jdk1.7 之後,

開始逐步去永久代,就不會產生內存溢出。

方法區用於存放 Class 的相關信息,如類名、訪問修飾符、常量池、欄位描述、方法描述等,如果動態生成大量的 Class 文件,也會產生內存溢出。常見的場景還有:大量 JSP 或動態產生 JSP 文件的應用(JSP 第一次運行時需要編譯為 java 類)、基於 OSGi 的應用(即

使是同一個類文件,被不同的類加載器加載也會視為不同的類)。

24、JVM 如何加載類的?

JVM 類加載機制分為五個部分:加載,驗證,準備,解析,初始化。

加載

加載是類加載過程中的一個階段, 這個階段會在內存中生成一個代表這個類 java.lang.Class

對象, 作為方法區這個類的各種數據的入口。注意這裡不一定非得要從一個 Class 文件獲取,這裡既可以從 ZIP 包中讀取(比如從 jar 包和 war 包中讀取),也可以在運行時計算生成(動態代理),也可以由其它文件生成(比如將 JSP 文件轉換成對應的 Class 類)。

驗證

這一階段的主要目的是為了確保 Class 文件的字節流中包含的信息是否符合當前虛擬機的要

求,並且不會危害虛擬機自身的安全。

準備

準備階段是正式為類變量分配內存並設置類變量的初始值階段,即在方法區中分配這些變量所使用的內存空間。注意這裡所說的初始值概念,比如一個類變量定義為:

實際上變量 v 在準備階段過後的初始值為 0 而不是 8080, 將 v 賦值為 8080 的 put static

指令是程序被編譯後, 存放於類構造器方法之中。

但是注意如果聲明為: public static finaint v = 8080;

在編譯階段會為 v 生成 ConstantValue 屬性,在準備階段虛擬機會根據 ConstantValue 屬

性將 v 賦值為 8080。

解析

解析階段是指虛擬機將常量池中的符號引用替換為直接引用的過程。符號引用就是 class 文件中的 public static int v = 8080;

實際上變量 v 在準備階段過後的初始值為 0 而不是 8080, 將 v 賦值為 8080 的 put static

指令是程序被編譯後, 存放於類構造器方法之中。但是注意如果聲明為:

在編譯階段會為 v 生成 ConstantValue 屬性,在準備階段虛擬機會根據 ConstantValue 屬

性將 v 賦值為 8080。

初始化

初始化階段是類加載最後一個階段,前面的類加載階段之後,除了在加載階段可以自定義類加載器以外,其它操作都由 JVM 主導。到了初始階段,才開始真正執行類中定義的 Java 程序代碼。

25、自己寫過 String 類能加載嗎,之前的 String 是什麼時候加載進去的?

不能加載,因為雙親委派機制,JVM 出於安全性的考慮,全限定類名相同的 String 是不能被加載的。

java.lang.String 會被頂級類加載器 Bootstrap Classloader 加載。當 class 文件被加載到 內存中時,類文件常量池中的其他常量會加載到運行時常量池,但是字符串常量不會。它會首 先在堆區中創建一個字符串對象,然後再把這個對象的引用保存到全局字符串常量池中。

26、描述 ThreadLocal(線程本地變量)的底層實現原理及常用場景?

實現原理

每個 Thread 線程內部都有一個 ThreadLocalMap;以線程作為 key,泛型作為 value,

可以理解為線程級別的緩存。每一個線程都會獲得一個單獨的 map。

提供了 set 和 get 等訪問方法,這些方法為每個使用該變量的線程都存有一份獨立的副本,因此 get 方法總是返回由當前執行線程在調用 set 時設置的最新值。

應用場景:

JDBC 連接

Session 管理

Spring 事務管理

調用鏈,參數傳遞

AOP

ThreadLoca是一個解決線程並發問題的一個類,用於創建線程的本地變量,我們知道一個

對象的所有線程會共享它的全局變量,所以這些變量不是線程安全的,我們可以使用同步技術。但是當我們不想使用同步的時候,我們可以選擇 ThreadLocal變量。例如,由於 JDBC 的連接對象不是線程安全的,因此,當多線程應用程式在沒有協同的情況下,使用全局變量時,就不是線程安全的。通過將 JDBC 的連接對象保存到 ThreadLocal中,每個線程都會擁有屬於自己的連接對象副本。

27、什麼是微服務架構?

微服務架構就是將單體的應用程式分成多個應用程式,這多個應用程式就成為微服務,每個微服務運行在自己的進程中,並使用輕量級的機制通信。這些服務圍繞業務能力來劃分,並通過自動化部署機制來獨立部署。這些服務可以使用不同的程式語言,不同資料庫,以保證最低限度的集中式管理。

28、微服務有哪些特點?

解耦 – 系統內的服務很大程度上是分離的。因此,整個應用程式可以輕鬆構建,更改和

擴展

組件化 – 微服務被視為可以輕鬆更換和升級的獨立組件

業務能力 – 微服務非常簡單,專注於單一功能

自治 – 開發人員和團隊可以彼此獨立工作,從而提高速度

持續交付 – 通過軟體創建,測試和批准的系統自動化,允許頻繁發布軟體

責任 – 微服務不關注應用程式作為項目。相反,他們將應用程式視為他們負責的產品

分散治理 – 重點是使用正確的工具來做正確的工作。這意味著沒有標準化模式或任何技

術模式。開發人員可以自由選擇最有用的工具來解決他們的問題

敏捷 – 微服務支持敏捷開發。任何新功能都可以快速開發並再次丟棄

29、Lambda 表達式是啥?優缺點?

lambda 表達式,也被稱為閉包,它是推動 Java 8 發布的最重要新特性。lambda 允許把函數作為一個方法的參數(函數作為參數傳遞進方法中),使用 Lambda 表達式可以使代碼變的更加簡潔緊湊。

優點:

代碼更加簡潔

減少匿名內部類的創建,節省資源

使用時不用去記憶所使用的接口和抽象函數

缺點:

不易於後期維護,必須熟悉 lambda 表達式和抽象函數中參數的類型。

可讀性差:

若不用並行計算,很多時候計算速度沒有比傳統的 for 循環快。(並行計算有時需要預熱才顯示出效率優勢)不容易調試。

若其他程式設計師沒有學過 lambda 表達式,代碼不容易讓其他語言的程式設計師看懂。

30、講一下 Lambda 的表達式作用域(Lambda Scopes)。

訪問局部變量

我們可以直接在 lambda 表達式中訪問外部的局部變量:但是和匿名對象不同的是,這裡的變量可以不用聲明為 final,該代碼同樣正確,不過這裡的變量必須不可被後面的代碼修改(即隱性的具有 fina的語義)

訪問欄位和靜態變量

與局部變量相比,我們對 lambda 表達式中的實例欄位和靜態變量都有讀寫訪問權限。

該行為和匿名對象是一致的。

訪問默認接口方法

無法從 lambda 表達式中訪問默認方法。

31、MySQ事務的特性有什麼,說一下分別是什麼意思?

原子性:即不可分割性,事務要麼全部被執行,要麼就全部不被執行。

一致性或可串性:事務的執行使得資料庫從一種正確狀態轉換成另一種正確狀態。

隔離性:在事務正確提交之前,不允許把該事務對數據的任何改變提供給任何其他事務。

持久性:事務正確提交後,其結果將永久保存在資料庫中,即使在事務提交後有了其他故

障,事務的處理結果也會得到保存。

關鍵字: