面試-java

Java

Java語言的理解

平臺無關係(跨平臺,一次編譯到處運行)
GC(垃圾回收機制,不需要去手動的釋放內存)
語言特性(泛型,反射,lambda)
面向對象(封裝,繼承,多態)
類庫(併發,集合庫)
異常處理

跨平臺

Javac編譯,生成字節碼文件,JVM解析,轉換成特定平臺的執行指令
Java原碼首先被編譯成字節碼,再由不同平臺的JVM進行解析,Java語言在不同的平臺上運行時不需要進行重新編譯,Java虛擬機在執行字節碼的時候,把字節碼轉換成具體平臺上的機器指令。

關於JVM的問題

JVM如何加載.class文件?JVM在內存裏一直運行

Engine:引擎

在這裏插入圖片描述

反射

JAVA反射機制在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取消息以及動態調用對象方法的功能稱爲java語言的反射機制

類加載

類從編譯到執行的過程

編譯器將xxx.java源文件編譯爲xxx.class字節碼文件
ClassLoader將字節碼轉換爲JVM中的Class<xxx>對象
JVM利用Class<xxx>對象實例化爲xxx對象

談談ClassLoader

ClassLoader在java中有着非常重要的作用,它主要工作在Class裝載的加載階段,其主要作用是從系統外部獲得Class二進制數據流,它是Java的核心組件,所有的Class都是由ClassLoader進行加載的,ClassLoader負責通過將Class文件裏的二進制數據流裝載進系統,然後交給Java虛擬機進行連接、初始化等操作

ClassLoader的種類

BootStrapClassLoader:C++編寫,加載核心庫java.*
ExtClassLoader:Java編寫,加載擴展庫javax.*
AppClassLoader:Java編寫,加載程序所在目錄
自定義ClassLoader:Java編寫,定製化加載

談談類加載器的雙親委派機制

在這裏插入圖片描述

爲什麼要使用雙親委派機制取加載類

避免多份同樣字節碼的加載

類的加載方式

隱式加載:new
顯示加載:loadClass,forName等,通過構造器,可以創建帶參的實例化對象

loadClass和forName的區別

類的裝載過程:
# 加載
通過ClassLoader加載class文件字節碼,生成class對象

# 鏈接
校驗:檢查加載的class的正確性和安全性
準備:爲類變量分配存儲空間並設置類變量初始值
解析:JVM將常量池內的符號引用轉換爲直接引用

# 初始化
執行類變量賦值和靜態代碼塊

兩者的區別:
Class.forName得到的class已經初始化完成的
ClassLoader.loadClass得到的class是還沒有鏈接的

Java內存模型

在這裏插入圖片描述

程序計數器

當前線程所執行的字節碼行號指示器(邏輯)
改變計數器的值來選取下一條需要執行的字節碼指令
和線程是一對一的關係即“線程私有”
對Java方法計數,如果是Native方法則計數器值爲undefined
不會發生內存泄露

Java虛擬機棧(Stack)

# Java方法執行的內存模型

# 包含多個棧幀
局部變量表,操作棧、動態連接。返回地址
局部變量表:包含方法執行過程中的所有變量
操作數棧:入棧、出棧、複製、交換、產生消費變量

本地方法棧

與虛擬機棧相似,主要作用於標註了native的方法

元空間(MetaSpace)與永久代(PermGen)的區別

元空間使用本地內存,而永久代使用的是jvm的內存
解決了空間不足的問題
# MetaSpace相比PermGen的優勢
字符串常量池存在永久代中,容易出現性能問題和內存溢出
類和方法的信息大小難易確定,給永久代的大小指定帶來困難
永久代會爲GC帶來不必要的複雜性
方便HotSpot與其他JVM如Jrockit的集成

Java堆(Heap)

對象實例的分配區域
GC管理的主要區域

JVM三大新能調優參數-Xmx -Xmx -Xss

java -Xms128m -Xmx128x -Xss256k -jar xxx.jar
-Xss:規定了每個線程虛擬機棧(堆棧)的大小
-Xms:堆的初始值
-Xmx:推能達到的最大值

Java內存模型中堆和棧的區別-內存分配策略

靜態存儲:編譯時確定每個數據目標在運行時的存儲空間需求
棧式存儲:數據區需求在編譯時未知,運行時模塊入口前確定
堆式存儲:編譯時或運行時模塊入口都無法確定,動態分配

Java內存模型中推和棧的區別

聯繫:引用對象、數組時,棧裏定義變量保存堆中目標的首地址
Person p = new Person()
棧內存			堆內存
p	------>  使用new開闢的內存空間

管理方式:棧自動釋放,堆需要GC
空間大小:棧比堆小
碎片相關:棧產生的碎片遠小於堆
分配方式:棧支持靜態和動態分配,而堆僅支持動態分配
效率:棧的效率比堆高

Java垃圾回收機制

對象被判定爲垃圾的標準

沒有被其他對象引用

判定對象是否爲垃圾的算法

引用計數算法
可達性分析算法

# 引用計數算法
判斷對象的引用數量
	通過判斷對象的引用數量來決定對象是否可以被回收
	每個對象實例都有一個引用計數器,被引用則+1,完成引用則-1
	任何引用計數爲0的對象實例可以被當做垃圾收集
優點:執行效率高,程序執行受影響較小
缺點:無法檢測出循環引用的情況,導致內存泄露

可達性分析算法

在這裏插入圖片描述

通過判斷對象的引用鏈是否可達來決定對象是否可以被回收

# 可以作爲GC Roob的對象
虛擬機棧中引用的對象(棧幀總的本地變量表)
方法區中的常量引用的對象
方法區中的類靜態屬性引用的對象
本地方法棧中JNI(Native方法)的引用對象
活躍線程的引用對象

談談你瞭解的垃圾回收算法

# 標記-清除算法(Mark and Sweep)
標記:從根集合進行掃描,對存活的對象進行標記
清除:對堆內存從頭到尾進行線性遍歷,回收不可達對象內存
缺點:碎片化,導致回收之後,出現很多不連續的內存空間

# 複製算法(Copying)
分爲對象面和空閒面
對象在對象面上創建
存活的對象被從對象面複製到空閒面
將對象面所有對象內存清除
# 優點
解決碎片化問題
順序分配內存,簡單高效
適用於對象存活率低的場景

# 標記-整理算法(Compacting)
標記:從根集合進行掃描,對存活的對象進行標記
清除:移動所有存活的對象,且按照內存地址次序依次排列,然後將末端內存地址以後的內存全部回收
# 優點
避免內存的不連續性
不用設置兩塊內存互換
適用於存活率高的場景

# 分代收集算法(Generational Collector)
垃圾回收算法的組合拳
按照對象生命週期的不同劃分區域以採用不同的垃圾回收算法
目的:提高JVM的回收效率
JDK8以後分爲:年輕代(存活率低,複製算法)和老年代(存活率高,標記-整理算法),沒有永久區了

java垃圾回收的種類

# 垃圾回收的種類,分代收集算法
Minor GC: 年輕代GC
Full GC:老年代GC
# 年輕代
儘可能快速地收集掉那些生命週期短的對象
1個Enden區(開始創建的對象都在Enden區,當進行一次垃圾回收(Minor GC)時,把還存活的對象複製到任意的一個Survivor區)
兩個Survivor區(當進行一次垃圾回收時,一個Survivor區會把還存活的對象,複製到另一個Survivor區,並且年齡會加1)

# 對象如何晉升到老年代
經歷一定Minor次數依然存活的對象
Survivor區中存放不下的對象
新生成的大對象(-XX:+PretenuerSizeThreshold)
# 常用的調優參數
-XX:SurvivorRatio:Eden和Survivor的比值,默認8:1:1
-XX:NewRatio:老年代和年輕代內存大小的比例
-XX:MaxTenuringThreshold:對象從年輕代晉升到老年代經過的GC次數的最大閾值

# 老年代
存放聲明週期較長的對象
標記-清理算法
標記-整理算法
Full GC和Major GC
Full GC比Major GC慢,但執行頻率低、

# 觸發Full GC的條件
老年代空間不足
永久代空間不足(針對jak7以前的版本,jdk8之後沒有永久代空間了)
GMS GC時出現promotion failed, concurrent mode failure
Minor GC晉升到老年代的平均大小大於老年代的剩餘空間
調用System.gc()
使用RMI來進行RPC或管理JDK應用,每小時執行1次Full GC

# Stop-the-World
JVM由於要執行GC而停止了應用程序的執行
任何一種GC算法中都會發生
多數GC優化通過減少Stop-the-World發生的時間來提高程序性能

# Safepoint
分析過程中對象引用關係不會發生變化的點
產生Safepoint的地方:方法調用;循環跳轉;異常跳轉等
安全點數量得適中

JVM運行的模式

java -version # 查看jvm運行時的模式

server:啓動慢,運行速度快,重量級的虛擬機,做了更多的優化
client:啓動快,運行速度慢,輕量級

年輕代常見的垃圾收集器

當執行垃圾回收時,會暫停所有用戶的線程,暫停的時間100ms以內,可以接受的
# Serial收集器(-XX:+UseSerialGC,複製算法)
單線程收集,進行垃圾收集時,必須暫停所有工作線程
簡單高效,Client模式下默認的年輕代收集器

# ParNew收集器(-XX:+UseParNewGC,複製算法)
多線程收集,其餘的行爲、特點和Serial收集器一樣
單核執行效率不如Serial,在多核下執行纔有優勢

# Parallel Scavenge收集器(-XX:UseParallelGC,複製算法)
吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)
比起關注用戶線程停頓時間,更關注系統的吞吐量
在多核下執行纔有優勢,Server模式下默認的年輕代收集器 
使用參數可以進行調優,交給虛擬機自己進行調優,-XX:+UseAdaptiveSizePolicy

老年代常見的垃圾收集器

# Serial Old收集器(-XX:+UseSerialOldGC,標記-整理算法)
單線程收集,進行垃圾收集時,必須暫停所有工作線程
簡單高效,Client模式下默認的老年代收集器

# Parallel Old收集器(-XX:+UseParallelOldGC,標記-整理算法)
多線程,吞吐量優先

# CMS收集器(-XX:UseConcMarkSweepGC,標記-清除算法)
初始化標記:stop-the-world
併發標記:併發追溯標記,程序不會停頓
併發預清理:查找執行併發標記階段從年輕代晉升到老年代的對象
重寫標記:暫停虛擬機,掃描CMS堆中的剩餘對象
併發清理:清理垃圾對象,程序不會停頓
併發重置:重置CMS收集器的數據結構

G1收集器(年輕和老年)

# G1收集器(-XX:UseG1GC,複製+標記-整理算法)
Garbage First收集器的特點
並行和併發
分代收集
空間整理
可預測的停頓

# Garbage First收集器
將整個Java堆內存劃分成多個大小相等的Region
年輕代和老年代不在物理隔離

垃圾收集器之間的聯繫

在這裏插入圖片描述

GC相關的面試題

# Object的finalize()方法的作用是否與C++的析構函數作用相同
與C++的析構函數不同,析構函數調用確定,而它的是不確定的
將未引用的對象放置於F-Queue隊列
方法執行隨時可能會被終止
給予對象最後一次重生的機會

# java中的強引用,軟引用,弱引用,虛引用有什麼用
# 強引用(Strong Reference)
最普遍的引用:Object obj = new Object()
拋出OutOfMemoryError終止程序也不會回收具有強引用的對象
通過將對象設置爲null來弱化引用,使其被回收

# 軟引用(Soft Reference)
對象處在有用但非必須的狀態
只有當內存空間不足時,GC會回收該引用的對象的內存
可以用來實現高速緩存
String str = new String("abc");  // 強引用
SoftReference<String> softRef = new SoftReference<String>(str); // 軟引用

# 弱引用(Weak Reference)
非必須的對象,比軟引用更弱一些
GC時會被回收
被回收的概率也不大,因爲GC線程優先級比較低
適用於引用偶爾被使用且不影響垃圾收集的對象
String str = new String("abc");  // 強引用
WeakReference<String> softRef = new WeakReference<String>(str); // 弱引用

# 虛引用(PhantomReference)
不會決定對象的聲明週期
任何時候都可能被垃圾收集器回收
跟蹤對象被垃圾收集器回收的活動,其哨兵作用
必須和引用隊列ReferenceQueue聯合使用
String str = new String("abc"); 
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(str, queue);

引用隊列(ReferenceQueue):無實際存儲結構,存儲邏輯依賴於內部節點之間的關係來表達

強引用 > 軟引用 > 弱引用 > 虛引用
引用類型 被垃圾回收時間 用途 生存時間
強引用 從來不會 對象的一般狀態 JVM停止運行時終止
軟引用 在內存不足時 對象緩存 內存不足時終止
弱引用 在垃圾回收時 對象緩存 gc運行後終止
虛引用 Unknown 標記、哨兵 Unknown

多任務

進程和線程的區別

# 進程
進程獨佔內存空間,保存各自運行狀態,相互間不干擾且可以互相切換,爲併發處理任務提供了可能

# 線程
共享進程的內存資源,相互間切換更快速,支持更細粒度的任務控制,使進程內的子任務得以併發執行

進程是資源分配的最小單位,線程是CPU調度的最小單位
所有與進程相關的資源,都被記錄在PCB中
進程是搶佔處理機的調度單位;線程屬於某個進程,共享其資源
# PCB裏有:
描述信息、控制信息、資源信息、CPU現場

# 總結
線程不能看做獨立應用,而進程可看做獨立應用
進程有獨立的地址空間,相互不影響,線程只是進程的不同執行路徑
線程沒有獨立的地址空間,進程的程序比多線程程序健壯
進程的切換比線程的切換開銷大

進程和線程的關係

Java對操作系統提供的功能進行封裝,包括進程和線程
運行一個程序會產生一個進程,進程包含至少一個線程
每個進程對應一個JVM實例,多個線程共享JVM裏的堆
Java採用單線程編程模型,程序會自動創建主線程
主線程可以創建子線程,原則上要後於子線程完成執行

Thread中的start和run方法區別

調用start()方法會創建一個新的子線程並啓動
run()方法只是Thread的一個普通方法的調用

Thread和Runnable是什麼關係

Thread是實現了Runnable接口的類,使得run支持多線程
因類的單一繼承原則,推薦多使用Runnable接口
MyRunnable myr1 = new MyRunnable();  // MyRunnable是實現Runnable接口的類裏的run方法
Thread t1 = new Thread(myr1);
t1.start(); 

如何給run()方法傳參

實現的方式主要有三種:
構造函數傳參
成員變量傳參
回調函數傳參

如何實現處理線程的返回值

實現的方式主要有三種:
主線程等待法
使用Thread類的join()阻塞當前線程以等待子線程處理完畢
通過Callable接口實現:通過FutureTask Or 線程池獲取

線程的狀態

# 六個狀態
新建(New):創建後尚未啓動的線程的狀態
運行(Runnable):包含Running和Ready
無限期等待(Waiting):不會被分配CPU執行時間,需要顯示被喚醒
沒有設置Timeout參數的Object.wait()方法
沒有設置Timeout參數的Thread.join()方法
LockSupport.park()方法
限期等待(Timed Waiting):在一定時間後會由系統自動喚醒
阻塞(Bolcked):等待獲取排它鎖
結束(Terminated):已終止線程的狀態,線程已經結束執行

sleep和wait的區別

# 基本差別
sleep是Thread類的方法,wait是Object類中定義的方法
sleep()方法可以在任何地方使用
wait()方法只能在synchronized方法或synchronized塊中使用,只能獲取鎖了,此時等待才能釋放鎖

# 最主要的本質區別
Thread.sleep只會讓出CPU,不會導致鎖行爲的改變
Object.wait不僅讓出CPU,還會釋放已經佔有的同步資源鎖

notify和notifyAll的區別

# 瞭解兩個基本概念
# 鎖池EntryList
假設線程A已經擁有了某個對象(不是類)的鎖,而其它線程B、C想要調用這個對象的某個synchronized方法(或者塊),由於B、C線程在進入對象synchronized方法(或者塊)之前必須先獲得該對象鎖的擁有權,而恰巧對象的鎖目前正被線程A所佔用,此時B、C線程就會被阻塞,進入一個地方去等待鎖的釋放。這個地方便是該對象的鎖池

# 等待池WaitSet
假設線程A調用了某個對象的wait()方法,線程A就會釋放該對象的鎖,同時線程A就進入到了該對象的等待池中,進入到等待池中的線程不會去競爭該對象的鎖

# notifyAll
notifyAll會讓所有處於等待池的線程全部進入鎖池去競爭獲取鎖的機會

# notify
notify只會隨機選取一個出去等待池中的線程進入鎖池取競爭獲取鎖的機會

yield

# 概念
當調用Thread.yield()函數時,會給線程調度器一個當前線程願意讓出CPU使用的暗示,但是線程調度器可能會忽略這個暗示

如何中斷線程

# 目前使用的方法
調用interrupt(),通知線程應該中斷了
1.如果線程處於被阻塞狀態,那麼線程將立即退出被阻塞狀態,並拋出一個InterruptException異常
2.如果線程處於正常活動狀態,那麼會將該線程的終端的標誌設置爲true。被設置終端標誌的線程將繼續正常運行,不受影響

需要被調用的線程配合中斷
1.在正常運行任務時,經常檢查本線程的中斷標誌位,如果被設置了中斷標誌就自行停止線程
2.如果線程處於正常活動狀態,那麼會將該線程的中斷標誌設置爲true。被設置終端標誌的線程將繼續正常運行,不受影響

在這裏插入圖片描述

synchronized

線程安全問題的主要誘因:
存在共享數據(也稱臨界資源)
存在多條線程共同操作這些共享數據

解決問題的根本方法:
同一時刻有且只有一個線程在操作共享數據,其他線程必須等到該線程處理完數據後再對共享數據進行操作
互斥鎖的特性
互斥性:即在同一時間只允許一個線程持有某個對象鎖,通過這種特性來實現多線程的協調機制,這樣在同一時間只有一個線程對需要同步的代碼塊(複合操作)進行訪問,互斥性也稱爲操作的原子性

可見性:必須確保在鎖被釋放之前,對共享變量所做的修改,對於隨後獲取該鎖的另一個線程是可見的(即在獲得鎖時應獲得最新共享變量的值),否則另一個線程可能是在本地緩存的某個副本上繼續操作,從而引起不一致

synchronized鎖的不是代碼,鎖的都是對象
獲取鎖
根據獲取鎖的分類:獲取對象鎖和獲取類鎖
獲取對象鎖的兩種用法
1、同步代碼塊(synchronized(this),synchronized(類實例對象)),鎖的是小括號()中的實例對象
2、同步非靜態方法(synchronized method),鎖是當前對象的實例對象
public synchronized void SyncTask(){}  // 同步非靜態方法

獲取類鎖的兩種用法
1、同步代碼塊(synchronized(類.class)),鎖是小括號()中類對象(Class 對象)
2、同步靜態方法(synchronized static method),鎖是當前對象的類對象(Class對象)
對象鎖和類鎖的總結
1、有線程訪問對象的同步代碼塊時,另外的線程可以訪問該對象的非同步代碼塊
2、若鎖住的是同一個對象,一個線程在訪問對象的同步代碼塊時,另一個訪問對象的同步代碼塊的線程會被阻塞
3、若鎖住的是同一個對象,一個線程在訪問對象的同步方法時,另一個訪問對象同步方法的線程會被阻塞
4、若鎖住的是同一個對象,一個線程在訪問對象的同步代碼塊時,另一個訪問對象同步方法的線程會被阻塞,反之亦然
5、同一類的不同對象的對象鎖互不干擾
6、類鎖由於也是一種特殊的對象鎖,因此表現和上述1,2,3,4一致,而由於一個類只有一把對象鎖,所以同一個類的不同對象使用類鎖將會是同步的
7、類鎖和對象鎖互不干擾
synchronized底層實現原理
# Monitor
Monitor:每個java對象天生自帶了一把看不見的鎖
Monitor鎖的競爭、獲取和釋放

# 什麼是重入
從互斥鎖的設計上來說,當一個線程視圖操作一個由其他線程持有的對象鎖的臨界資源時,將會處於阻塞狀態,但當一個線程再次請求自己持有對象鎖的臨界資源時,這種情況屬於重入

# 爲什麼會對synchronized嗤之以鼻
早期版本中,synchronized屬於重量級鎖,依賴於Mutex Lock實現
線程之間的切換需要從用戶態轉換到核心態,開銷較大

# 自旋鎖與自適應自旋鎖
自旋鎖:許多情況下,共享數據的鎖定狀態持續時間較短,切換線程不值得
通過讓線程執行忙循環等待鎖的釋放,不讓出CPU
缺點:若鎖被其他線程長時間佔用,會帶來許多性能上的開銷
synchronized和ReentrantLock的區別
synchronized是關鍵字,ReentrantLock是類
ReentrantLock可以對獲取鎖的等待時間進行設置,避免死鎖
ReentrantLock可以獲取各種鎖的信息
ReentrantLock可以靈活地實現多路通知
機制:sync操作Mark Word,lock調用Unsafe類的park()方法

線程池

線程池的種類
利用Executors創建不同的線程池滿足不同場景的需求
1.newFixedThreadPool(int nThreads)指定工作線程數量的線程池
2.newCachedThreadPool()處理大量短時間工作任務的線程池
	a.試圖緩存線程並重用,當無緩存線程可用時,就會創建新的工作線程
	b.如果線程閒置的時間超過閾值,則會被終止並移出緩存
	c.系統長時間閒置的時候,不會消耗什麼資源
3.newSingleThreadExecutor()創建唯一的工作者線程來執行任務,如果線程異常結束,會有另一個線程取代它
4.newSingleScheduledExecutor()與newScheduledThreadPool(int corePoolSize)定時或者週期性的工作調度,兩者的區別在於單一工作線程還是多線程
5.newWorkStealingPool()內部會創建ForkJoinPool,利用working-stealing算法,並行地處理任務,不保證處理順序
fork/join框架
把大任務分割成若干個小人物並行執行,最終彙總每個小任務結果後得到大任務結果的框架
爲什麼要使用線程池
降低資源消耗
提高線程的可管理性
ThreadPoolExecutor的構造函數
corePoolSize:核心線程數量
maximumPoolSize:線程不夠用時能夠創建的最大線程數
workQueue:任務等待隊列
keepAliveTime:搶佔的順序不一定,看運氣
threadFactory:創建新線程,Executors.defaultThreadFactory()
handle:線程池的飽和策略
	AbortPolicy:直接拋出異常,這是默認策略
	CallerRunsPolicy:用調用者所在的線程來執行任務
	DiscardOldestPolicy:丟棄隊列中靠最前的任務,並執行當前任務
	DiscardPolicy:直接丟棄任務
	實現RejectedExecutionHandler接口的自定義handler
新任務提交execute執行後的判斷
如果運行的線程少於corePoolSize,則創建新線程來處理任務,即使線程池中的其他線程是空閒的;
如果線程池中的線程數量大於等於corePoolSize且小於maximumPoolSize,則只有當workQueue滿時才創建新的線程去處理任務
如果設置的corePoolSize和maximumPoolSize相同,則創建的線程池的大小是固定的,這時如果有新任務提交,若workQueue未滿,則將請求workQueue中,等待有空閒的線程取從workQueue中取任務並處理
如果運行的線程數量大於等於maximumPoolSize,這時如果workQueue已經滿了,則通過handler所指定的策略來處理任務;
線程池的狀態
RUNNING:能接受新提交的任務,並且也能處理阻塞隊列中的任務
SHUTDOWN:不在接受新提交的任務,但可以處理存量任務
STOP:不在接受新提交的任務,也不處理存量任務
TIDYING:所有的任務都已終止
TERMINATED:terminated()方法執行完後進入該狀態
線程池的大小如何選定
CPU密集型:線程數=按照核數或者核數+1設定
I/O密集型:線程數=CPU核數*(1 + 平均等待時間/平均工作時間)

String StringBuffer StringBuilder

String:線程安全,節省空間
StringBuffer:高效,但線程不安全
StringBuilder:高效且線程安全

Java異常

異常梳理機制主要回答了三個問題

what:異常類型回答了上面被拋出異常
where:異常堆棧跟蹤回答了在哪拋出
why:異常信息回答了爲什麼被拋出

Error和Exception的區別

Error:程序無法處理的系統錯誤,編譯器不做檢查
Exception:程序可以處理的異常,捕獲後可能恢復
總結:前者是程序無法處理的錯誤,後者是可以處理的異常

從責任角度看:
1、Error數據JVM需要負擔的責任;
2、RuntimeException是程序應該負擔的責任;
3、Checked Exception可檢查異常是Java編譯器應該負擔的責任

Java的異常處理機制

拋出異常:創建異常對象,交由運行時系統處理  throws
捕獲異常:尋找合適的異常護理器處理異常,否則終止運行 try...catch

try-catch的性能

Java異常處理消耗性能的地方:
try-catch塊影響JVM的優化
異常對象實例需要保存棧塊照等信息,開銷較大

微服務

# Spring Cloud
eureka:註冊中心
ribbon: 負載均衡,放註冊到eureka裏面的服務,均衡起來,例如server1裏對應兩個ip,訪問兩次,每個執行一次
hystrix:熔斷,防止一個服務出問題,一致卡主,出現雪崩,在一定的時間,就返回
feign:服務調用
zuul:網關,攔截不合理的請求
客戶端訪問ip,先經過nginx反向代理到網關zuul,然後這裏有負載均衡ribbon和熔斷hystrix,去eureka裏面調取相應的服務;

數據結構考點

數組和鏈表的區別
鏈表的操作,如反轉,鏈表環路檢測,雙向鏈表,循環鏈表相關操作
隊列,棧的應用
二叉樹的遍歷方式及其遞歸和非遞歸的實現
紅黑樹的旋轉

算法考點

內部排序:如遞歸排序,交換排序(冒泡、快排)、選擇排序、插入排序;
外部排序:應掌握如何利用有限的內存配合海量的外部存儲來處理超大的數據集,寫不出也要有相關的思路

考點擴展
那些排序是不穩定的,穩定意味着什麼
不同數據集,各種排序最好或最差的情況
如何優化算法

Mybatis的基本原理

# 工廠模式
# 生成SqlSession使用了工廠模式
優勢:解耦(降低類之間的依賴關係)

# 代理模式
# 創建Dao接口實現類使用了代理模式
優勢:不修改原碼的基礎上對已有的方法進行增強


# 1.讀取配置文件
# InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//通過類加載器來讀取配置文件
is = MybatisTest.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");

# 2.創建SqlSessionFactory對象
builder = new SqlSessionFactoryBuilder();
factory = builder.build(is);

# 3.使用工廠生產SqlSession對象
sqlSession = factory.openSession();  # 裏面加true,就可以自動提交,但有時候不好

# 4.使用SqlSession創建IUserDao接口的代理對象
userDao = sqlSession.getMapper(IUserDao.class);

FastDFS文件存儲系統

中間件

RMQ[RabbitMQ]

# AMQP協議
高級消息隊列協議

發佈訂閱模式
通過交換機與隊列綁定的key,發佈到隊列裏
交換機常用的有三種:
direct,點對點,需要全部配備到key了,才把消息發到該隊列裏
fanout,發佈的消息,綁定的隊列都收到消息
topic,匹配,發佈的消息,與該key匹配上的隊列收到消息

解決消息丟失
# ack(消息確認)
# 持久化
# 發送消息前,將消息持久化到數據庫,並記錄消息狀態(可靠消息服務)
# 生產者確認(publisher confirm)

zookeeper

協調中心,調度中心

kafka

生產消費模式,訂閱一個topic,發佈的消息到該topic,訂閱該topic的就收到了該消息
高吞吐,kafka集羣

ES[elasticsearch]

儲存數據用的,存儲的數據類型爲json
put /index/type/1 存儲數據,可以寫json的格式去查詢
get /index/type/1 獲取數據
delete /index/type/1 刪除數據
head /index/type/1 判斷數據是否存在,返回狀態碼,200或404

# 分詞
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章