1、TCP 和 UDP 區(qū)別?
- TCP 基于連接,UDP 基于無連接。
- TCP 要求系統(tǒng)資源較多,UDP 較少。
- UDP 程序結(jié)構(gòu)較簡單。
- TCP 保證數(shù)據(jù)正確性,UDP 可能丟包。
- TCP 保證數(shù)據(jù)順序,UDP 不保證。
2、TCP/IP 協(xié)議涉及哪幾層架構(gòu)?
- 應(yīng)用層
- 傳輸層
- 互連網(wǎng)絡(luò)層
- 網(wǎng)絡(luò)接口層。
3、描述下 TCP 連接 4 次揮手的過程?為什么要 4 次揮手?
因為 TCP 是全雙工,每個方向都必須進行單獨關(guān)閉。關(guān)閉連接時,當(dāng) Server 端收到 FIN
報文時,很可能并不會立即關(guān)閉 SOCKET,所以只能先回復(fù)一個 ACK 報文,告訴 Client
端,”你發(fā)的 FIN 報文我收到了”。只有等到 Server 端所有的報文都發(fā)送完了,我才能發(fā)
送 FIN 報文,因此不能一起發(fā)送。故需要四步握手。
4、計算機插上電源操作系統(tǒng)做了什么?
- 加電––––打開電源開關(guān),給主板和內(nèi)部風(fēng)扇供電。
- 啟動引導(dǎo)程序––––CPU 開始執(zhí)行存儲在 ROM BIOS 中的指令。
- 開機自檢––––計算機對系統(tǒng)的主要部件進行診斷測試。
- 加載操作系統(tǒng)––––計算機將操作系統(tǒng)文件從磁盤讀到內(nèi)存中。
- 檢查配置文件,定制操作系統(tǒng)的運行環(huán)境––––讀取配置文件,根據(jù)用戶的設(shè)置對操作
系統(tǒng)進行定制。 - 準(zhǔn)備讀取命令和數(shù)據(jù)––––計算機等待用戶輸入命令和數(shù)據(jù)。
5、Linux 操作系統(tǒng)設(shè)備文件有哪些?
字符設(shè)備、塊設(shè)備。
6、多線程同步有哪些方法?
- 使用 synchronized 關(guān)鍵字
- wait 和 notify
- 使用特殊域變量 volatile 實現(xiàn)線程同步
- 使用重入鎖實現(xiàn)線程同步
- 使用局部變量來實現(xiàn)線程同步
- 使用阻塞隊列實現(xiàn)線程同步
- 使用原子變量實現(xiàn)線程同步
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 中調(diào)用了 inner,outer 先鎖住了 lock,這樣 inner 就不能再獲取 lock。其實調(diào)用
outer 的線程已經(jīng)獲取了 lock 鎖,但是不能在 inner 中重復(fù)利用已經(jīng)獲取的鎖資源,這種
鎖即稱之為不可重入可重入就意味著:線程可以進入任何一個它已經(jīng)擁有的鎖所同步著的代碼
塊。
synchronized、ReentrantLock 都是可重入的鎖,可重入鎖相對來說簡化了并發(fā)編程的開發(fā)。
9、創(chuàng)建線程的三個方法是什么?
- 通過繼承 Thread 類創(chuàng)建線程類。
- 實現(xiàn) Runnable 接口創(chuàng)建線程類。
- 通過 Callable 和 Future 接口創(chuàng)建線程。
10、Java 怎么獲取多線程的返回值?
- 主線程等待。
- 使用 Thread 的 join 阻塞當(dāng)前線程等待。
- 實現(xiàn) Callable 接口(通過 FutureTask 或線程池的 Future)。
11、線程池有哪幾種創(chuàng)建方式?
Java 通過 Executors(jdk1.5 并發(fā)包)提供四種線程池,分別為:
- newCachedThreadPool 創(chuàng)建一個可緩存線程池,如果線程池長度超過處理需要,可靈
活回收空閑線程,若無可回收,則新建線程。 - newFixedThreadPool 創(chuàng)建一個定長線程池,可控制線程最大并發(fā)數(shù),超出的線程會在隊
列中等待。 - newScheduledThreadPool 創(chuàng)建一個定長線程池,支持定時及周期性任務(wù)執(zhí)行。
- newSingleThreadExecutor 創(chuàng)建一個單線程化的線程池,它只會用唯一的工作線程來執(zhí)
行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級)執(zhí)行。
12、線程池參數(shù)有哪些?
- corePoolSize 核心線程大小。
- maximumPoolSize 線程池最大線程數(shù)量。
- keepAliveTime 空閑線程存活時間。
- unit 空間線程存活時間單位。
- workQueue 工作隊列。
- threadFactory 線程工廠。
- handler 拒絕策略。
13、線程池拒絕策略有哪些?
-
ThreadPoolExecutor.AbortPolicy
:丟棄任務(wù)并拋出RejectedExecutionException
異常
(默認(rèn)拒絕策略)。 -
ThreadPoolExecutor.DiscardPolicy
:丟棄任務(wù),但是不拋出異常。 -
ThreadPoolExecutor.DiscardOldestPolicy
:丟棄隊列最前面的任務(wù),然后重新提交被
拒絕的任務(wù)。 -
ThreadPoolExecutor.CallerRunsPolicy
:由調(diào)用線程(提交任務(wù)的線程)處理該任務(wù)。
14、你認(rèn)為對線程池的核心參數(shù)實現(xiàn)自定義可配置,三個核心參數(shù)是?
- corePoolSize : 核心線程數(shù)線程數(shù)定義了最小可以同時運行的線程數(shù)量。
- maximumPoolSize : 當(dāng)隊列中存放的任務(wù)達(dá)到隊列容量的時候,當(dāng)前可以同時運行的線
程數(shù)量變?yōu)樽畲缶€程數(shù)。 - workQueue: 當(dāng)新任務(wù)來的時候會先判斷當(dāng)前運行的線程數(shù)量是否達(dá)到核心線程數(shù),如果
達(dá)到的話,信任就會被存放在隊列中。
15、ThreadPoolExecutor 線程池,corePoolSize=5,maximumPoolSize=10,queueCapacity=10,有 20 個耗時任務(wù) 交給這個線程池執(zhí)行,線程池會如何執(zhí)行這 20 個任務(wù)?
- 如果當(dāng)前線程數(shù)<
corePoolSize
,如果是則創(chuàng)建新的線程執(zhí)行該任務(wù) 。 - 如果當(dāng)前線程數(shù)>=
corePoolSize
,則將任務(wù)存入BlockingQueue
。 - 如果阻塞隊列已滿,且當(dāng)前線程數(shù)<
maximumPoolSize
,則新建線程執(zhí)行該任務(wù)。 - 如果阻塞隊列已滿,且當(dāng)前線程數(shù)>=
maximumPoolSize
,則拋出異常 。 -
RejectedExecutionException
,告訴調(diào)用者無法再接受任務(wù)了。
16、給用戶發(fā)消息任務(wù)超出隊列,你用哪個拒絕策略?有其他方法嗎 ?
ThreadPoolExecutor.CallerRunsPolicy
- 無界隊列(LinkedBlockingQuene),繼續(xù)添加任務(wù)到阻塞隊列中等待執(zhí)行。
- 用消息隊列存任務(wù)數(shù)據(jù),線程池慢慢處理。
17、Java8 新特性有哪些了解?
- 接口的默認(rèn)方法
- Lambda 表達(dá)式
- 函數(shù)式接口
- 方法和構(gòu)造函數(shù)引用
- Lamda 表達(dá)式作用域
- 內(nèi)置函數(shù)式接口
- Optional
- Streams(流)
- Parallel Streams(并行流)
- Maps
- Date API(日期相關(guān) API)
- Annotations(注解)
18、什么時候用多線程、為什么要設(shè)計多線程?
- 高并發(fā)
系統(tǒng)接受實現(xiàn)多用戶多請求的高并發(fā)時,通過多線程來實現(xiàn)。
線程后臺處理大任務(wù)
一個程序是線性執(zhí)行的。如果程序執(zhí)行到要花大量時間處理的任務(wù)時,那主程序就得等待其執(zhí)
行完才能繼續(xù)執(zhí)行下面的。那用戶就不得不等待它執(zhí)行完。
這時候可以開線程把花大量時間處理的任務(wù)放在線程處理,這樣線程在后臺處理時,主程序也
可以繼續(xù)執(zhí)行下去,用戶就不需要等待。線程執(zhí)行完后執(zhí)行回調(diào)函數(shù)。 - 大任務(wù)
大任務(wù)處理起來比較耗時,這時候可以起到多個線程并行加快處理(例如:分片上傳)。
好處:可以提高 CPU 的利用率。在多線程程序中,一個線程必須等待的時候,CPU 可以運
行其他的線程而不是等待,這樣就大大提高了程序的效率。也就是說允許單個程序創(chuàng)建多個并
行執(zhí)行的線程來完成各自的任務(wù)。
19、多線程越多效率越高嗎?
不是
當(dāng)線程總數(shù)較少時,線程越多,效率越高。
當(dāng)線程總數(shù)較多時,由于線程本身調(diào)用耗時,線程越多,效率越低。
線程數(shù)越多會造成:
- 線程的生命周期開銷非常高
- 消耗過多的 CPU 資源。
20、多線程會產(chǎn)生哪些并發(fā)問題 ?
安全性問題:在單線程系統(tǒng)上正常運行的代碼,在多線程環(huán)境中可能會出現(xiàn)意料之外的結(jié)果。
活躍性問題:不正確的加鎖、解鎖方式可能會導(dǎo)致死鎖 or 活鎖問題。
性能問題:多線程并發(fā)即多個線程切換運行,線程切換會有一定的消耗并且不正確的加鎖。
21、Mybatis 如何將對象轉(zhuǎn)換成 SQL?
SQL 綁定是在加載 Mybatis 配置文件,然后掃描到哪個 mapper 子節(jié)點,再加載mapper 映射文件,掃描里面的 SQL 節(jié)點,然后封裝成對象(MappedStatement,在這個對象的 SqlSource 封裝著 sql 語句)。所有的配置信息保存在 Configuration 類,最后動
態(tài)代理執(zhí)行的時候,取出來封裝 sql 的對象,執(zhí)行 sql。
22、虛擬內(nèi)存是什么,虛擬內(nèi)存的原理是什么?
虛擬內(nèi)存是計算機系統(tǒng)內(nèi)存管理的一種技術(shù)。
虛擬內(nèi)存有以下兩個優(yōu)點:
- 虛擬內(nèi)存地址空間是連續(xù)的,沒有碎片。
- 虛擬內(nèi)存的最大空間就是 cup 的最大尋址空間,不受內(nèi)存大小的限制,能提供比內(nèi)存更大的地址空間。
當(dāng)每個進程創(chuàng)建的時候,內(nèi)核會為每個進程分配虛擬內(nèi)存,這個時候數(shù)據(jù)和代碼還在磁盤上,當(dāng)運行到對應(yīng)的程序時,進程去尋找頁表,如果發(fā)現(xiàn)頁表中地址沒有存放在物理內(nèi)存上,而是在磁盤上,于是發(fā)生缺頁異常,于是將磁盤上的數(shù)據(jù)拷貝到物理內(nèi)存中并更新頁表,下次再訪問該虛擬地址時就能命中了。
23、棧會溢出嗎?什么時候溢出?方法區(qū)會溢出嗎?
棧是線程私有的,它的生命周期與線程相同,每個方法在執(zhí)行的時候都會創(chuàng)建一個棧幀,用來存儲局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口等信息。局部變量表又包含基本數(shù)據(jù)類型,對象引用類型。如果線程請求的棧深度大于虛擬機所允許的最大深度,將拋出StackOverflowError 異常,方法遞歸調(diào)用產(chǎn)生這種結(jié)果。如果 Java 虛擬機??梢詣討B(tài)擴展,并且擴展的動作已經(jīng)嘗試過,但是無法申請到足夠的內(nèi)存去完成擴展,或者在新建立線程的時候沒有足夠的內(nèi)存去創(chuàng)建對應(yīng)的虛擬機棧,那么 Java 虛擬機將拋出一個 OutOfMemory 異常。(線程啟動過多)。
方法區(qū)會發(fā)生溢出。
HotSpot jdk1.7 之前字符串常量池是方法區(qū)的一部分,方法區(qū)叫做“永久代”,在 1.7 之
前無限的創(chuàng)建對象就會造成內(nèi)存溢出,提示信息:PermGen space 而是用 jdk1.7 之后,
開始逐步去永久代,就不會產(chǎn)生內(nèi)存溢出。
方法區(qū)用于存放 Class 的相關(guān)信息,如類名、訪問修飾符、常量池、字段描述、方法描述等,
如果動態(tài)生成大量的 Class 文件,也會產(chǎn)生內(nèi)存溢出。常見的場景還有:大量 JSP 或動態(tài)
產(chǎn)生 JSP 文件的應(yīng)用(JSP 第一次運行時需要編譯為 java 類)、基于 OSGi 的應(yīng)用(即
使是同一個類文件,被不同的類加載器加載也會視為不同的類)。
24、JVM 如何加載類的?
JVM 類加載機制分為五個部分:加載,驗證,準(zhǔn)備,解析,初始化。
加載
加載是類加載過程中的一個階段, 這個階段會在內(nèi)存中生成一個代表這個類 java.lang.Class
對象, 作為方法區(qū)這個類的各種數(shù)據(jù)的入口。注意這里不一定非得要從一個 Class 文件獲取,
這里既可以從 ZIP 包中讀?。ū热鐝?jar 包和 war 包中讀?。?,也可以在運行時計算生成
(動態(tài)代理),也可以由其它文件生成(比如將 JSP 文件轉(zhuǎn)換成對應(yīng)的 Class 類)。
驗證
這一階段的主要目的是為了確保 Class 文件的字節(jié)流中包含的信息是否符合當(dāng)前虛擬機的要
求,并且不會危害虛擬機自身的安全。
準(zhǔn)備
準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量的初始值階段,即在方法區(qū)中分配這些變量所
使用的內(nèi)存空間。注意這里所說的初始值概念,比如一個類變量定義為:
實際上變量 v 在準(zhǔn)備階段過后的初始值為 0 而不是 8080, 將 v 賦值為 8080 的 put static
指令是程序被編譯后, 存放于類構(gòu)造器方法之中。
但是注意如果聲明為:
public static final int v = 8080;
在編譯階段會為 v 生成 ConstantValue 屬性,在準(zhǔn)備階段虛擬機會根據(jù) ConstantValue 屬
性將 v 賦值為 8080。
解析
解析階段是指虛擬機將常量池中的符號引用替換為直接引用的過程。符號引用就是 class 文件
中的
public static int v = 8080;
實際上變量 v 在準(zhǔn)備階段過后的初始值為 0 而不是 8080, 將 v 賦值為 8080 的 put static
指令是程序被編譯后, 存放于類構(gòu)造器方法之中。但是注意如果聲明為:
在編譯階段會為 v 生成 ConstantValue 屬性,在準(zhǔn)備階段虛擬機會根據(jù) ConstantValue 屬
性將 v 賦值為 8080。
初始化
初始化階段是類加載最后一個階段,前面的類加載階段之后,除了在加載階段可以自定義類加
載器以外,其它操作都由 JVM 主導(dǎo)。到了初始階段,才開始真正執(zhí)行類中定義的 Java 程序
代碼。
25、自己寫過 String 類能加載嗎,之前的 String 是什么時候加載進去的?
不能加載,因為雙親委派機制,JVM 出于安全性的考慮,全限定類名相同的 String 是不能
被加載的。
java.lang.String 會被頂級類加載器 Bootstrap Classloader 加載。當(dāng) class 文件被加載到
內(nèi)存中時,類文件常量池中的其他常量會加載到運行時常量池,但是字符串常量不會。它會首
先在堆區(qū)中創(chuàng)建一個字符串對象,然后再把這個對象的引用保存到全局字符串常量池中。
26、描述 ThreadLocal(線程本地變量)的底層實現(xiàn)原理及常用場景?
實現(xiàn)原理:
- 每個 Thread 線程內(nèi)部都有一個 ThreadLocalMap;以線程作為 key,泛型作為 value,
可以理解為線程級別的緩存。每一個線程都會獲得一個單獨的 map。 - 提供了 set 和 get 等訪問方法,這些方法為每個使用該變量的線程都存有一份獨立的副
本,因此 get 方法總是返回由當(dāng)前執(zhí)行線程在調(diào)用 set 時設(shè)置的最新值。
應(yīng)用場景: - JDBC 連接
- Session 管理
- Spring 事務(wù)管理
- 調(diào)用鏈,參數(shù)傳遞
- AOP
ThreadLocal 是一個解決線程并發(fā)問題的一個類,用于創(chuàng)建線程的本地變量,我們知道一個
對象的所有線程會共享它的全局變量,所以這些變量不是線程安全的,我們可以使用同步技術(shù)。
但是當(dāng)我們不想使用同步的時候,我們可以選擇 ThreadLocal 變量。例如,由于 JDBC 的
連接對象不是線程安全的,因此,當(dāng)多線程應(yīng)用程序在沒有協(xié)同的情況下,使用全局變量時,
就不是線程安全的。通過將 JDBC 的連接對象保存到 ThreadLocal 中,每個線程都會擁有
屬于自己的連接對象副本。
27、什么是微服務(wù)架構(gòu)?
微服務(wù)架構(gòu)就是將單體的應(yīng)用程序分成多個應(yīng)用程序,這多個應(yīng)用程序就成為微服務(wù),每個微
服務(wù)運行在自己的進程中,并使用輕量級的機制通信。這些服務(wù)圍繞業(yè)務(wù)能力來劃分,并通過
自動化部署機制來獨立部署。這些服務(wù)可以使用不同的編程語言,不同數(shù)據(jù)庫,以保證最低限
度的集中式管理。文章來源:http://www.zghlxwxcb.cn/news/detail-554361.html
28、微服務(wù)有哪些特點?
- 解耦 – 系統(tǒng)內(nèi)的服務(wù)很大程度上是分離的。因此,整個應(yīng)用程序可以輕松構(gòu)建,更改和
擴展 - 組件化 – 微服務(wù)被視為可以輕松更換和升級的獨立組件
- 業(yè)務(wù)能力 – 微服務(wù)非常簡單,專注于單一功能
- 自治 – 開發(fā)人員和團隊可以彼此獨立工作,從而提高速度
- 持續(xù)交付 – 通過軟件創(chuàng)建,測試和批準(zhǔn)的系統(tǒng)自動化,允許頻繁發(fā)布軟件
- 責(zé)任 – 微服務(wù)不關(guān)注應(yīng)用程序作為項目。相反,他們將應(yīng)用程序視為他們負(fù)責(zé)的產(chǎn)品
- 分散治理 – 重點是使用正確的工具來做正確的工作。這意味著沒有標(biāo)準(zhǔn)化模式或任何技
術(shù)模式。開發(fā)人員可以自由選擇最有用的工具來解決他們的問題 - 敏捷 – 微服務(wù)支持敏捷開發(fā)。任何新功能都可以快速開發(fā)并再次丟棄
29、Lambda 表達(dá)式是啥?優(yōu)缺點?
lambda 表達(dá)式,也被稱為閉包,它是推動 Java 8 發(fā)布的最重要新特性。lambda 允許把函
數(shù)作為一個方法的參數(shù)(函數(shù)作為參數(shù)傳遞進方法中),使用 Lambda 表達(dá)式可以使代碼變
的更加簡潔緊湊。文章來源地址http://www.zghlxwxcb.cn/news/detail-554361.html
- 優(yōu)點:
- 代碼更加簡潔
- 減少匿名內(nèi)部類的創(chuàng)建,節(jié)省資源
- 使用時不用去記憶所使用的接口和抽象函數(shù)
- 缺點:
- 不易于后期維護,必須熟悉 lambda 表達(dá)式和抽象函數(shù)中參數(shù)的類型
- 可讀性差
- 若不用并行計算,很多時候計算速度沒有比傳統(tǒng)的 for 循環(huán)快。(并行計算有時需要預(yù)熱
才顯示出效率優(yōu)勢) - 不容易調(diào)試。
- 若其他程序員沒有學(xué)過 lambda 表達(dá)式,代碼不容易讓其他語言的程序員看懂。
30、講一下 Lambda 的表達(dá)式作用域(Lambda Scopes)。
- 訪問局部變量
- 我們可以直接在 lambda 表達(dá)式中訪問外部的局部變量:但是和匿名對象不同的是,這里
的變量可以不用聲明為 final,該代碼同樣正確,不過這里的變量必須不可被后面的代碼
修改(即隱性的具有 final 的語義)
- 我們可以直接在 lambda 表達(dá)式中訪問外部的局部變量:但是和匿名對象不同的是,這里
- 訪問字段和靜態(tài)變量
- 與局部變量相比,我們對 lambda 表達(dá)式中的實例字段和靜態(tài)變量都有讀寫訪問權(quán)限。
該行為和匿名對象是一致的。
訪問默認(rèn)接口方法 - 無法從 lambda 表達(dá)式中訪問默認(rèn)方法。
- 與局部變量相比,我們對 lambda 表達(dá)式中的實例字段和靜態(tài)變量都有讀寫訪問權(quán)限。
31、MySQL 事務(wù)的特性有什么,說一下分別是什么意思?
- 原子性:即不可分割性,事務(wù)要么全部被執(zhí)行,要么就全部不被執(zhí)行。
- 一致性或可串性。事務(wù)的執(zhí)行使得數(shù)據(jù)庫從一種正確狀態(tài)轉(zhuǎn)換成另一種正確狀態(tài)。
- 隔離性。在事務(wù)正確提交之前,不允許把該事務(wù)對數(shù)據(jù)的任何改變提供給任何其他事務(wù)。
持久性。事務(wù)正確提交后,其結(jié)果將永久保存在數(shù)據(jù)庫中,即使在事務(wù)提交后有了其他故
障,事務(wù)的處理結(jié)果也會得到保存
到了這里,關(guān)于2021 【阿里】面試真題的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!