網(wǎng)站LOGO透明底色PNG格式怎么做的最新足球賽事
文章目錄
- java 基礎
- 1、JDK 和 JRE的區(qū)別
- 2、= = 和equals的區(qū)別
- 3、String、StringBuffer、StringBuilder
- 4、String str = “a”、 new String(“a”)一樣嗎?
- 5、ArrayList 和 LinkedList的區(qū)別?
- 6、HashMap的原理與實現(xiàn)
- 6.1、容量與擴容
- 6.2、擴容機制
- 7、HashMap中的put方法執(zhí)行過程
- 8、ConcurrentHashMap工作原理
- 9、SimpleDateFormat是線程安全的嗎?
- 10、java.util.Date 與 java.sql.Date 有什么區(qū)別?
- 11、對象被置為null,垃圾回收器會立即釋放占用的內存嗎?
- 12、java的數(shù)據(jù)結構有哪些
- 13、java中異常分為幾種
- 14、Error與Exception的區(qū)別
- 15、java的單模式
- 16、哪些集合是線程安全的?
- 17、synchronized原理
- 18、volatile有什么用
- 19、synchronized關鍵字可以實現(xiàn)什么類型的鎖?
- 20、怎么創(chuàng)建不可修改的集合
- 21、sleep和wait的區(qū)別
- 22、jvm內存結構
- 23、運行時數(shù)據(jù)區(qū)
- 24、堆結構(jdk1.8)
- 25、java垃圾回收算法
- 26、垃圾回收器
- 27、GC Roots 可以是哪些?
- 28、引用類型有哪些
- 29、java的IO流分為幾種?
- 30、BIO、NIO、AIO
- 31、NIO直接緩沖區(qū)與非直接緩沖區(qū)
- 32、NIO內存映射到緩存
- 33、序列化和反序列化
- 網(wǎng)絡基礎
- 1、TCP 三次握手
- 2、TCP 四次揮手關閉連接
- 3、TCP與UDP的區(qū)別
- 4、請求出現(xiàn)503是什么問題
- spring
- 1、spring boot啟動流程
- 2、spring bean的實例化
- 3、Spring的ioc
- 4、Spring的aop
- 5、Spring的類加載機制
- 6、Java類加載機制
- 7、雙親委派模型
- 8、Spring怎么解決循環(huán)依賴
- 9、Spring 用到了哪些設計模式?
- 10、設計模式的六大原則
- 11、spring的事務和分布式事務
- 12、分布式事務的實現(xiàn)方式
- 13、分布式鎖?
- mysql
- 1、事務四大特性
- 2、事務的隔離級別
- 3、臟讀、重復讀、幻讀
- 4、B樹和B+樹的區(qū)別
- 5、mysql為什么用B+樹
- 6、mysql鎖有哪些
- 7、mysql的redolog、binlog、undolog
- 8、mysql二階段提交
- 9、mysql什么時候會索引失效
- redis
- 1、緩存雪崩、緩存擊穿、緩存穿透
- 2、會員中有大量要過期怎么處理
- 多線程
- 1、線程同步的方法
- 2、什么是ThreadLocal,以及其實現(xiàn)原理?
- 3、為什么要使用線程池
- 4、線程池執(zhí)行過程
- 5、線程池的創(chuàng)建方式
- 6、線程池的7個參數(shù)
- 7、線程池隊列有哪些
- 8、線程池拒絕策略有哪些
- 9、線程池的關閉
- 10、使用無界隊列的線程池會導致內存飆升嗎?
- 11、線程創(chuàng)建的幾種方式
- 12、Future有什么用
- 13、FutureTask有什么用
- 14、線程的生命周期(狀態(tài))
- 15、 i++是線程安全的嗎
- 16、可重入鎖ReentrantLock
- 16.1、Synchronized和ReentrantLock的相同
- 16.2、Synchronized和ReentrantLock的不同
- 17、synchronized可重入鎖的實現(xiàn)原理
- Activiti流程引擎
- 1、Activiti工作流的主要組件
- 2、Activiti工作流有什么優(yōu)勢
- 3、Activiti工作流service有哪些
- 4、流程實例和執(zhí)行對象的區(qū)別
- 5、工作流中一個任務完成后,存在多條連線,如何處理
- 6、Activiti工作流中排他網(wǎng)關和并行網(wǎng)關都能執(zhí)行什么功能
- 7、分配個人任務的三種方式
- 8、個人任務和組任務的查詢一樣嗎?
- 綜合性問題
- 1、生產(chǎn)環(huán)境發(fā)生內存泄露怎么排查問題?
java 基礎
1、JDK 和 JRE的區(qū)別
2、= = 和equals的區(qū)別
= = 比基本類型:比較值,
= = 比引用類型:比較引用。
equals本質上就是= =,String、integer等重寫了equals方法,把它變成了值比較。
3、String、StringBuffer、StringBuilder
String 每次操作都會生成新的String對象
StringBuffer 線程安全的,所有公開方法都是 synchronized 修飾的
StringBuilder 非線程安全的,性能更高一些
4、String str = “a”、 new String(“a”)一樣嗎?
前者會放到常量池,后者放到堆內存
5、ArrayList 和 LinkedList的區(qū)別?
ArraList 是基于數(shù)組實現(xiàn)的線性表,尾部插入和數(shù)據(jù)訪問效率高
LinkedList是雙向鏈表,中間插入和頭部插入效率高,查詢效率低
6、HashMap的原理與實現(xiàn)
- 數(shù)組:HashMap底層由一個數(shù)組組成,數(shù)組的每個元素稱為一個桶(存一個或多個Entry)。
- 鏈表:多個鍵值對映射到同一個桶,會發(fā)生哈希沖突。哈希沖突后使用鏈表將沖突的鍵值對連接起來。這就是所謂的“數(shù)組 + 鏈表”的散列數(shù)據(jù)結構。
- 紅黑樹:Java 1.8 開始,當鏈表的長度超過一定閾值(默認為 8)時,鏈表會轉換為紅黑樹。紅黑樹是一種自平衡的二叉查找樹,能夠提高 HashMap 的查詢效率。
6.1、容量與擴容
HashMap 的默認大小是16(16是為了確保算出來的值足夠隨機),
當容量到達閾值的時候會觸發(fā)擴容,閾值=容量加載因子,160.75=12。
每次擴容是之前容量的2倍。
6.2、擴容機制
JDK 1.7:空參構造函數(shù),內部是空數(shù)組,第一次put初始化數(shù)組。
JDK1.8 : 空參構造函數(shù),內部是null,第一次put初始化數(shù)組。
7、HashMap中的put方法執(zhí)行過程
1、判斷鍵值對數(shù)組是否為空(null)或者length=0,是的話就執(zhí)行resize()方法進行擴容。
2、不是就根據(jù)鍵值key計算hash值得到插入的數(shù)組索引i。
3、判斷索引i這個位置是否是null,如果是,就新建節(jié)點。如果不是,判斷首個元素是否和key一樣,一樣就直接覆蓋。
4、如果位置I的首個元素和key不一樣,判斷是否是紅黑樹,如果是紅黑樹,直接在樹中插入鍵值對。
5、如果不是紅黑樹,開始遍歷鏈表,判斷鏈表長度是否大于8,如果大于8就轉成紅黑樹,在樹中執(zhí)行插入操作,如果不是大于8,就在鏈表中執(zhí)行插入;在遍歷過程中判斷key是否存在,存在就直接覆蓋對應的value值。
6、插入成功后,就需要判斷實際存在的鍵值對數(shù)量size是否超過了最大容量threshold,如果超過了,執(zhí)行resize方法進行擴容。
8、ConcurrentHashMap工作原理
Jdk1.7
JDK1.8
JDK1.7,結構為segment+數(shù)組+鏈表,通過繼承 ReentrantLock加分段鎖。每次需要加鎖的操作鎖住的是一個 segment,這樣只要保證每個 Segment 是線程安全的。
JDK1.8,放棄了鎖分段的概念,使用Node+CAS+Synchronized的方式實現(xiàn)并發(fā),的結構為數(shù)組+鏈表+紅黑樹
9、SimpleDateFormat是線程安全的嗎?
DateFormat的所有實現(xiàn)都是線程不安全的。
10、java.util.Date 與 java.sql.Date 有什么區(qū)別?
java.util.Date表示一個日期和時間,通常用于表示一個時間戳。
java.sql.Date是java.util.Date的子類,它只表示日期,不包含時間。
11、對象被置為null,垃圾回收器會立即釋放占用的內存嗎?
不會,這個對象可能被回收
12、java的數(shù)據(jù)結構有哪些
線性表、鏈表、棧、隊列、map、樹
13、java中異常分為幾種
編譯時異常、運行時異常
編譯時異常:空指針異常、數(shù)值轉換異常、數(shù)組越界異常等
14、Error與Exception的區(qū)別
- Error和Exception都繼承了Throwable類 。
異??梢酝ㄟ^程序捕捉。 - Error是系統(tǒng)錯誤,通常比較嚴重。
15、java的單模式
餓漢式:默認創(chuàng)建對象
懶漢式:第一次使用時創(chuàng)建對象
餓漢式:1、靜態(tài)變量,2、靜態(tài)代碼塊
懶漢式:3、靜態(tài)變量(初始化方法加載),4、同步方法,5、同步代碼塊
6、雙重檢查
7、靜態(tài)內部類(利用jvm對靜態(tài)內部類在使用時加載的機制)
8、枚舉
16、哪些集合是線程安全的?
1、Vector (vector比arraylist多個synchronized同步,因此系統(tǒng)開銷比arraylist大)
2、hashTable
3、ConcurrentHashMap
17、synchronized原理
synchronized主要有三種使用方式:修飾普通同步方法、修飾靜態(tài)同步方法、修飾同步方法塊。
鎖的升級過程:
1、無鎖,不鎖住資源,多個線程只有一個能修改資源成功,其他線程會重試;
2、偏向鎖,同一個線程獲取同步資源時,沒有別人競爭時,去掉所有同步操作,相當于沒鎖;
3、輕量級鎖,多個線程搶奪同步資源時,沒有獲得鎖的線程使用CAS自旋等待鎖的釋放;
4、重量級鎖,多個線程搶奪同步資源時,使用操作系統(tǒng)的互斥量進行同步,沒有獲得鎖的線程阻塞等待喚醒
synchronized關鍵字三大特性:
原子性(指令不可分割)、
可見性(其他線程可看見修改)、
有序性(代碼是順序執(zhí)行)
volatile關鍵字只能保證可見性和有序性,不能保證原子性,也稱為是輕量級的synchronized。
18、volatile有什么用
- 可見性:當一個線程修改了 volatile 變量的值,其他線程能夠立即看到修改后的值。
(這是因為 volatile 變量的讀寫操作不會被緩存在寄存器或其他處理器內部的緩存中,而是直接從內存中讀取或寫入。因此,使用 volatile 變量可以確保多線程之間的數(shù)據(jù)同步。) - 禁止指令重排序:編譯器或處理器可能會對代碼進行優(yōu)化,對指令進行重新排序,以提高執(zhí)行效率。volatile 變量的讀寫操作不會被重排序,這樣可以確保指令按照代碼中的順序執(zhí)行,避免了因指令重排序導致的數(shù)據(jù)不一致問題。
- 原子性:volatile 變量在讀寫操作時,具有原子性。這意味著,多個線程同時訪問 volatile 變量時,不會發(fā)生沖突。雖然 volatile 變量不保證復合操作的原子性(如自增或復合賦值操作),但簡單的讀寫操作具有原子性。
19、synchronized關鍵字可以實現(xiàn)什么類型的鎖?
悲觀鎖:每次訪問共享資源時都會上鎖。
非公平鎖:線程獲取鎖的順序并不一定是按照線程阻塞的順序。
可重入鎖:已經(jīng)獲取鎖的線程可以再次獲取鎖。
獨占鎖或者排他鎖:該鎖只能被一個線程所持有,其他線程均被阻塞
20、怎么創(chuàng)建不可修改的集合
List<String> list = new ArrayList<>();list.add("1");Collection<String> listC = Collections.unmodifiableCollection(list); // listC不可修改listC.add("2"); // listC 報錯
21、sleep和wait的區(qū)別
- Sleep是線程內停頓,不釋放鎖,自動喚醒,sleep 是 Thread 類的靜態(tài)本地方法,
- Wait要釋放鎖,必須放在 synchronized 塊里面,需要 notify/ notifyAll 進行喚醒,wait 是 Object 類的本地方法。Wait可能還是有機會重新競爭到鎖繼續(xù)執(zhí)行的。
22、jvm內存結構
1、程序計數(shù)器:指向當前線程正在執(zhí)行的字節(jié)碼指令的行號。
2、本地方法棧:Native方法。
3、棧(虛擬機棧):每個Java方法在被調用的時候都會創(chuàng)建一個棧幀,用來存儲局部變量表(八大原始類型、封裝類型)、作數(shù)棧、動態(tài)鏈接、方法出口。
4、堆:對象實例、數(shù)組
5、方法區(qū):各個線程共享的內存區(qū)域,存儲類的結構信息,例如運行時常量池,字段(通過引用常量池中的常量來描述)和方法等數(shù)據(jù),以及方法和構造函數(shù)的代碼,包括用于類和實例初始化以及接口初始化的特殊方法。
23、運行時數(shù)據(jù)區(qū)
24、堆結構(jdk1.8)
25、java垃圾回收算法
-
標記-清除算法:
1、標記,從根節(jié)點出發(fā)遍歷對象,對訪問過的對象打上標記
2、清除,對沒有標記的對象進行回收 -
標記-整理算法:
1、標記,從根節(jié)點出發(fā)遍歷對象,對訪問過的對象打上標記
2、讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存 -
復制算法:用在新生代,把可用的對象從一個地方拷貝到另一個地方
-
三色標記法:CMS、G1垃圾回收器都使用了三色標記法。
白色:沒有標記的對象(垃圾對象)
灰色:該對象已標記,對象下的屬性還沒全被標記
黑色:該對象已標記,對象下的屬性也全被標記 -
分代回收算法:堆空間分為新生代和老年代
Minor GC : 新生代回收
Major GC : 老年代回收,出現(xiàn)了 Major GC,經(jīng)常會伴隨至少一次的 Minor GC。
Full GC : 新生代 + 老年代回收 -
可達性分析算法:以GC Roots為起始點,從上至下的方式搜索被根對象集合所連接的目標對象是否可達。內存中的存活對象都會被根對象集合直接或間接連接著,搜索所走過的路徑稱為引用鏈。
26、垃圾回收器
JDK1到JDK13的發(fā)展歷程中,一共出現(xiàn)了10種垃圾回收器
- Serial(串行收集器):新生代,只使用一條GC線程進行垃圾回收,過程中暫停其他工作線程。
- Parallel Scavenge(并行收集器):新生代,復制算法實現(xiàn),并行多線程回收器,常用于新生代。
- CMS :老年代,標記-清除算法實現(xiàn)(最后會產(chǎn)生許多內存碎片,到達一定量時,交由串行收集器處理)。
- G1 :主要作用于老年代,標記-整理算法實現(xiàn)。
各個收集器的Full GC:
27、GC Roots 可以是哪些?
棧中引用的對象、本地方法棧內引用的對象、靜態(tài)屬性引用的對象、常量引用的對象、同步鎖 synchronized 持有的對象、虛擬機內部的引用、反映 java 虛擬機內部情況的 JMXBean、JVMTI 中注冊的回調、本地代碼緩存等
28、引用類型有哪些
強引用:new出來的對象就是強引用,垃圾回收器不會回收
軟引用:new SoftReference(),內存不足時回收
弱引用:第一次GC回收時,掃到了回收。ThreadLocal的map的key是弱引用
虛引用:虛引用主要用來跟蹤對象的回收,清理被銷毀對象的相關資源。
29、java的IO流分為幾種?
按功能分:輸入流、輸出流
按類型分:字節(jié)流(8個字節(jié)為單位)、字符流(16)
30、BIO、NIO、AIO
BIO:同步阻塞IO,使用簡單,并發(fā)處理能力低
NIO:同步非阻塞IO,通過channel實現(xiàn)多路復用
AIO:異步非阻塞IO,基于事件和回調機制
31、NIO直接緩沖區(qū)與非直接緩沖區(qū)
- 緩沖區(qū)分配方式:
非直接緩沖區(qū):通過allocate()方法分配緩沖區(qū),將緩沖區(qū)建立在 JVM 的內存中。
直接緩沖區(qū):通過allocateDirect()方法分配直接緩沖區(qū),將緩沖區(qū)建立在物理內存中。 - 數(shù)據(jù)傳輸效率:
非直接緩沖區(qū):在操作系統(tǒng)和 JVM 之間進行數(shù)據(jù)傳輸,可能涉及到內存復制操作,因此相對較慢。
直接緩沖區(qū):由于直接建立在物理內存中,可以減少內存復制操作,提高數(shù)據(jù)傳輸效率。
32、NIO內存映射到緩存
將文件或文件的一部分映射到內存中的技術。通過內存映射文件,可以以字節(jié)數(shù)組的方式訪問文件內容,而無需進行昂貴的系統(tǒng)調用。
33、序列化和反序列化
把當前jvm進程中的對象,傳輸?shù)搅硪粋€進程里面進行恢復。序列化后進行傳輸,恢復就是反序列化。
常用的序列化工具json、xml、kyro、hessian等
網(wǎng)絡基礎
1、TCP 三次握手
1、客戶端請求建立連接
2、服務端應答,并請求建立連接
3、客戶端確認客戶端應答
2、TCP 四次揮手關閉連接
1、客戶端請求斷開連接
2、服務端確認應答
3、服務端請求斷開連接
4、客戶端確認應答
3、TCP與UDP的區(qū)別
- TCP:面向連接的協(xié)議,一個TCP連接必須要經(jīng)過三次“對話”才能建立起來。TCP保證數(shù)據(jù)正確性、數(shù)據(jù)順序,
- UDP:一個非連接的協(xié)議,傳輸數(shù)據(jù)之前源端和終端不建立連接。UDP可能丟包、不保證順序;
4、請求出現(xiàn)503是什么問題
503 錯誤是 HTTP 協(xié)議中的一種服務器錯誤,表示服務器暫時無法處理請求。這個錯誤通常發(fā)生在服務器維護、過載或者遇到了意外的問題時。
- 1、確認問題:首先,確認問題是否存在??梢酝ㄟ^監(jiān)控系統(tǒng)、日志或者與前端開發(fā)人員溝通來了解是否存在 503 錯誤。
- 2、分析錯誤原因:一旦確認存在 503 錯誤,需要分析錯誤的原因。這可能包括服務器過載、硬件故障、軟件錯誤、配置問題等。
- 3、制定解決方案:根據(jù)錯誤原因,制定相應的解決方案。以下是一些建議:
如果是服務器過載,可以考慮增加服務器數(shù)量、優(yōu)化數(shù)據(jù)庫查詢、限制并發(fā)連接數(shù)等。
如果是硬件故障,及時更換硬件或升級服務器。
如果是軟件錯誤或配置問題,修復代碼或配置錯誤。
考慮使用負載均衡器分發(fā)請求,以避免單個服務器過載。
優(yōu)化代碼,減少不必要的資源消耗。 - 4、實施解決方案:根據(jù)解決方案,修改代碼、配置服務器或其他相關組件。
測試驗證:在實施解決方案后,需要對系統(tǒng)進行測試,確保 503 錯誤已得到解決,并且不會影響其他請求的正常處理。 - 5、預防措施:為防止 503 錯誤再次發(fā)生,可以采取以下措施:定期檢查、監(jiān)控系統(tǒng)、制定應急預案,以應對突發(fā)情況。
spring
1、spring boot啟動流程
1、首先從main找到run方法,在執(zhí)行run之前new一個springApplication對象
2、進入run方法,創(chuàng)建應用監(jiān)聽器
3、加載配置文件
4、加載應用上下文,當作run方法的返回對象
5、創(chuàng)建spring容器,實現(xiàn)自動配置和bean的實例化
2、spring bean的實例化
兩個階段:容器啟動階段、bean實例化階段
容器啟動階段:加載元數(shù)據(jù)、對各種處理器進行注冊、上下文初始化、事件廣播初始化
Bean實例化:
1、加載Bean定義:spring從配置文件或注解中加載bean定義
2、實例化Bean: 根據(jù)bean的定義,創(chuàng)建bean實例。如果bean定義中指定了初始化方法,spring會在實例化后調用這些方法。
3、屬性賦值:如果bean中定義了屬性,spring會使用屬性值或構造器參數(shù)對屬性進行賦值。
4、Bean注冊:將Bean實例注冊到Spring容器中,以便在其他地方使用。
3、Spring的ioc
ioc中文名控制反轉(另一名稱DI依賴注入)。IOC是指,利用反射的原理將創(chuàng)建對象的權利交給Spring容器,spring在運行的時候根據(jù)配置文件來動態(tài)的創(chuàng)建對象和維護對象之間的關系,實現(xiàn)了松耦合的思想。
4、Spring的aop
面向切行期間,不修改源碼對已有方法進行增強。
配置方式:基于注解配置aop、基于XML的Aop、編程式創(chuàng)建代理
- AOP有哪些實現(xiàn)方式?
AOP有兩種實現(xiàn)方式:靜態(tài)代理(編譯時增強)和動態(tài)代理(運行時創(chuàng)建)。 - 動態(tài)代理的兩種實現(xiàn)方式?
JDK動態(tài)代理:通過接口實現(xiàn),代理類根據(jù)目標類實現(xiàn)的接口動態(tài)生成,不需要自己編寫
CGLIB動態(tài)代理:通過繼承實現(xiàn)。
5、Spring的類加載機制
Springboot中的類SPI擴展機制
在springboot的自動裝配過程中,最終會加載META-INF/spring.factories文件,而加載的過程是由SpringFactoriesLoader加載的。從CLASSPATH下的每個Jar包中搜尋所有META-INF/spring.factories配置文件,然后將解析properties文件,找到指定名稱的配置后返回。需要注意的是,其實這里不僅僅是會去ClassPath路徑下查找,會掃描所有路徑下的Jar包,只不過這個文件只會在Classpath下的jar包中。
6、Java類加載機制
jvm的類加載器默認使用的是雙親委派模式。三種默認的類加載器 啟動類加載器、擴展類加載器、應用程序類加載器。每一個中類加載器都確定了從哪一些位置加載文件。也可以通過繼承java.lang.classloader實現(xiàn)自己的類加載器。
7、雙親委派模型
當一個類加載器收到類加載任務時,會先交給自己的父加載器去完成,因此最終加載任務都會傳遞到最頂層的啟動類加載器,只有當父加載器無法完成加載任務時,才會嘗試自己來加載。
8、Spring怎么解決循環(huán)依賴
A依賴于B,B依賴于C,C又依賴于A
解決辦法:
1、Spring首先從一級緩存“SingletonObjects”中獲取。
2、獲取不到并且對象正在創(chuàng)建中,就再從二級緩存“earlySingletonObjects”中獲取。
3、如果還是獲取不到且允許singletonFactories通過getObject()獲取,就從三級緩存singletonFactory.getObject()(三級緩存)獲取。
4、如果從三級緩存中獲取到就從singletonFactories中移除,并放入earlySingletonObjects中。其實也就是從三級緩存移動到了二級緩存。
無法解決的循環(huán)依賴:A依賴于B,B依賴于A
9、Spring 用到了哪些設計模式?
- 工廠模式:spring在使用getBean()調用獲得該bean時,會自動調用該bean的getObject()方法。每個 Bean 都會對應一個 FactoryBean,如 SqlSessionFactory 對應 SqlSessionFactoryBean。
- 單例模式:一個類僅有一個實例,提供一個訪問它的全局訪問點。
- 適配器模式:Spring提供了一個適配器接口,每一種 Controller 對應一種 HandlerAdapter 實現(xiàn)類,當請求過來,SpringMVC會調用getHandler()獲取相應的Controller,然后獲取該Controller對應的 HandlerAdapter,最后調用HandlerAdapter的handle()方法處理請求,實際上調用的是Controller的handleRequest()。每次添加新的 Controller 時,只需要增加一個適配器類就可以,無需修改原有的邏輯。
- 代理模式:spring 的 aop 使用了動態(tài)代理,有兩種方式Jdk動態(tài)代理和Cglib動態(tài)代理。
- 模板模式:Spring 中 jdbcTemplate、hibernateTemplate 等,就使用到了模板模式。
10、設計模式的六大原則
- 開閉原則: 一個軟件實體應該通過擴展來實現(xiàn)變化,而不是通過修改已有的代碼來實現(xiàn)變化
- 依賴倒轉原則: 面向接口編程
- 里氏代換原則: 只要父類能出現(xiàn)的地方,子類就可以出現(xiàn),而且替換為子類也不會產(chǎn)生任何錯誤或異常
- 單一職責: 一個類/方法盡可能只做一件事
- 迪米特法則: 對象與對象間因該盡可能獨立,少調用其他對象的方法
- 接口隔離原則: 每個接口的功能應該是獨立的
11、spring的事務和分布式事務
Spring里面的事務本質上是數(shù)據(jù)庫層面的事務,主要是針對單個庫中的對個表的操作。
分布式事務主要解決多個庫直接數(shù)據(jù)一致性問題。
12、分布式事務的實現(xiàn)方式
1、使用數(shù)據(jù)庫事務: MySQL 的 XA 事務、 Oracle 的 RAC 事務
2、分布式事務中間件:例如,可以使用 Spring 框架提供的分布式事務支持,通過配置事務管理器、事務傳播行為等來實現(xiàn)分布式事務。
3、使用消息隊列:將事務操作轉化為消息,通過消息隊列進行異步處理,保證事務的最終一致性。
4、采用分布式鎖:通過對分布式環(huán)境中的共享資源進行加鎖,保證事務的原子性和一致性??梢允褂萌?Redis、ZooKeeper 等分布式鎖實現(xiàn)。
5、采用分布式緩存:通過將數(shù)據(jù)緩存在分布式緩存中,減少對數(shù)據(jù)庫的訪問,提高并發(fā)性能,同時保證數(shù)據(jù)的一致性。如使用 Redis、Memcached 等分布式緩存技術。
6、使用 TCC機制:分為三個階段,分別在事務主動方、事務被動方和協(xié)調器之間進行。通過 try、commit 和 confirm 操作來保證分布式事務的一致性。
13、分布式鎖?
1、什么是分布式鎖?
系統(tǒng)內,有多個消費者,需要對同一共享數(shù)據(jù)并發(fā)訪問和消費時,會有線程安全問題。例如在秒殺、搶優(yōu)惠券等場景下,商品庫存的數(shù)量是有限的,在高并發(fā)下,會有"超買"或"超賣"的問題。因此我們需要使用鎖,解決多線程對共享數(shù)據(jù)并發(fā)訪問的線程安全問題。
2、為什么要用分布式鎖
當系統(tǒng)使用分布式架構時,服務會有多個實例存在。需要使用分布式鎖,保證一個資源在同一時間內只能被一個服務的同一個線程執(zhí)行。
3、redis分布式鎖
通過代碼調用setnx命令,只在鍵不存在的情況下, 將鍵的值設置為某個值。若鍵已經(jīng)存在, 則setnx命令不做任何動作。為了能處理"獲取該鎖的請求所在的服務實例宕機,會導致該資源被長期鎖住,其他請求無法獲取該鎖"這種情況,我們還需要設置超時時間。
4、redis分布式鎖缺陷
1、強依賴redis的可用性,一旦redis宕機,會導致業(yè)務系統(tǒng)不可用,因此最好搭建redis集群。
2、因為對鎖設置了超時時間,如果某次請求不能在該次限制時間內完成操作,也會導致在某些時刻,多 個請求獲取到鎖。
解決方案也很簡單,我們在調用setnx時,將值設置為該次請求線程的id,并且在服務實例內,設置一個守護線程,當鎖快要超時時,判斷請求是否完成,如果未完成,延長超時時間。
mysql
1、事務四大特性
原子性、
一致性(事務執(zhí)行之前數(shù)據(jù)庫是一致的,那么執(zhí)行后也是)、
隔離性(事務間隔離)、
持久性(數(shù)據(jù)的改變是持久的)
2、事務的隔離級別
讀未提交:能讀取到其他事務沒提交的,臟讀、不可重復讀、幻讀
讀已提交:讀取到其他事務提交后的,不可重復讀、幻讀
可重復讀:給事務讀取的數(shù)據(jù)加上版本號,一個事務內兩次讀取一致,幻讀
串行化:一個事務完成才能執(zhí)行下一個事務
3、臟讀、重復讀、幻讀
臟讀:讀到其他事務還沒有提交的,可能后面又發(fā)生了回滾或修改,就是臟數(shù)據(jù)
不可重復讀:同一條數(shù)據(jù),同一個事務中兩次讀取結果不一樣
幻讀:同一個事務兩次讀取的數(shù)據(jù)條數(shù)不一樣
4、B樹和B+樹的區(qū)別
- B樹特點:
1、節(jié)點是排序的
2、一個節(jié)點可以存多個元素,這多個元素也是排序了 - B+樹的特點:
1、有B樹的特點
2、葉子節(jié)點之間有指針
3、非葉子節(jié)點的元素,都會冗余在葉子節(jié)點上(也就是葉子節(jié)點中儲存了所有元素,并排了序的)
5、mysql為什么用B+樹
1、B+樹通過對數(shù)據(jù)進行排序可以提高查詢效率
2、一個節(jié)點儲存多個元素,(B樹節(jié)點索引+數(shù)據(jù),B+樹節(jié)點僅索引,葉子節(jié)點索引+數(shù)據(jù))使得B+樹不會太 高(一個innodb頁默認16k,一般兩層B+樹存2千萬左右數(shù)據(jù))
3、葉子節(jié)點存了所有數(shù)據(jù),可以很好的支持全表掃描、范圍查詢
4、由于B+樹不會太高,一般三層,B+樹的IO次數(shù)比較穩(wěn)定
6、mysql鎖有哪些
行鎖:鎖住一行數(shù)據(jù),并發(fā)度高
表鎖:鎖住整個表,并發(fā)讀低(MyISAM 存儲引擎只支持表鎖)
間隙鎖:鎖住某個區(qū)間
7、mysql的redolog、binlog、undolog
1、binlog用于記錄數(shù)據(jù)庫執(zhí)行的寫入性操作,只有在事務提交時才會記錄biglog,binlog日志有三種格式,分別為STATMENT、ROW和MIXED。(使用場景:主從復制、數(shù)據(jù)恢復)。
2、Redolog(InnoDB特有的)記錄數(shù)據(jù)頁的變更,而這種變更記錄是沒必要全部保存。mysql每執(zhí)行一條DML語句,先將記錄寫入redo log buffer,后續(xù)再一次性將記錄寫到redo log file。(因為Innodb是以頁為單位進行磁盤交互的,1、一個事務很可能只修改一個數(shù)據(jù)頁里面的幾個字節(jié),這個時候將完整的數(shù)據(jù)頁刷到磁盤,太浪費資源。2、一個事務可能涉及修改多個數(shù)據(jù)頁,并且這些數(shù)據(jù)頁在物理上并不連續(xù),使用隨機IO寫入性能太差)
注意:binlog和redo log二者同時記錄,才能保證當數(shù)據(jù)庫發(fā)生宕機重啟時,數(shù)據(jù)不會丟失。
redolog 事務日志、binlog數(shù)據(jù)庫變更的邏輯日志
3、undolog保證事務原子性,記錄了數(shù)據(jù)的邏輯變化。比如一條INSERT語句,對應一條DELETE的undo log,對于每個UPDATE語句,對應一條相反的UPDATE的undo log,這樣在發(fā)生錯誤時,就能回滾到事務之前的數(shù)據(jù)狀態(tài)。
8、mysql二階段提交
Mysql開啟了binlog日志時,那么提交事務時就要同時完成redolog和binlog的事務寫入。二段提交發(fā)生在redolog和binlog的日志寫入階段,為了滿足數(shù)據(jù)的一致性設計。
第一階段:prepare階段,事務操作記錄到redolog中 ,記錄為prepare狀態(tài)。
第二階段:commit階段,事務操作記錄到binlog中,把redolog的狀態(tài)改為commit。
如果在寫入redolog之前崩潰,redolog和binlog中為空,滿足一致性
如果在寫入redolog后,寫入binlog前崩潰,redolog中為prepare狀態(tài)狀態(tài),可根據(jù)redolog恢復。
如果的在binlog寫入后崩潰,那么redolog可以拿著事務id去執(zhí)行binlog的日志直接提交數(shù)據(jù)。
9、mysql什么時候會索引失效
1、沒有使用索引列作為where查詢條件
2、對索引列進行函數(shù)操作(字符串操作、日志操作)
3、對索引列進行類型轉換
4、Like查詢時以“%”開頭
5、查詢條件包括Or,or條件中的每個條件都不涉及索引列,mysql無法使用索引
6、當使用大范圍查詢的時候
redis
1、緩存雪崩、緩存擊穿、緩存穿透
緩存雪崩:大量key同時失效
擊穿:多個請求獲取一個key,key失效時發(fā)生擊穿到數(shù)據(jù)庫
穿透:緩存中沒有key,數(shù)據(jù)庫中也沒有,造成資源一直訪問數(shù)據(jù)庫
2、會員中有大量要過期怎么處理
1、系統(tǒng)不主動輪詢,等用戶登陸系統(tǒng)時觸發(fā)檢查(缺點:無法主動發(fā)送提醒)
2、用搜索引擎(如es),存儲一份會員ID和過期時間到搜索引擎中,搜索引擎能夠實現(xiàn)快速檢索
3、使用redis實現(xiàn),把id和過期時間存到redis中,使用redis過期提醒功能 ,當key過期后觸發(fā)過期事件。
4、使用MQ里面的延遲隊列,用戶開通會員后,計算會員過期時間,發(fā)送延遲消息到MQ里面,達到時間進行消費。
多線程
1、線程同步的方法
- Wait(): 讓線程等待,將線程存儲到一個線程池中。
- Notify(): 喚醒被等待的線程,通常都喚醒線程池中的第一個,讓被喚醒的線程處于臨時阻塞狀態(tài)。
- NotifyAll(): 喚醒(同一個鎖的)所有的等待線程。必須在同步代碼塊中調用此方法,否則拋出異常。wait()和notify()系列方法這樣設計的目的是防止死鎖或永久等待發(fā)生。notifyAll()執(zhí)行后,只有一個線程能得到鎖,其他沒有得到鎖的線程會繼續(xù)保持在等待狀態(tài)。
注意:
1、調用完notifyAll()方法后,同步代碼塊中的其他代碼,必須執(zhí)行完后才能將對象鎖釋放,而不是調用了notifyAll()方法后立即釋放。
2、在java中,Thread類線程執(zhí)行完run()方法后,一定會自動執(zhí)行notifyAll()方法。
2、什么是ThreadLocal,以及其實現(xiàn)原理?
ThreadLocal是一種線程隔離機制,提供了多線程環(huán)境下對于共享變量訪問的一個安全性。
在每個線程里面都有一個容器,來存儲共享變量的一個副本,然后每個線程只對自己的變量副本進行更新操作。
實現(xiàn)原理:
在Thread類里面有一個ThreadLocalMap,用來存儲共享變量的副本,線程僅對這個副本進行操作,不影響全局共享變量的值,實現(xiàn)數(shù)據(jù)隔離。
3、為什么要使用線程池
1、降低線程開啟關閉消耗的系統(tǒng)資源
2、提高系統(tǒng)響應速度(線程開啟響應速度慢)
3、線程管理(線程開啟、關閉、線程數(shù)量等)
4、線程池執(zhí)行過程
簡述:任務進線程池,先判斷核心線程是否滿了,滿了就進隊列,隊列滿了就看最大線程數(shù)是否已達到,達到了就按飽和策略處理。未達到飽和就創(chuàng)建線程執(zhí)行任務。
核心線程 - 隊列 - 最大線程數(shù) - 飽和策略
5、線程池的創(chuàng)建方式
1、固定大小線程池
2、緩存線程池
3、單線程線程池
4、延遲任務線程池
5、單線程延遲任務線程池
6、搶占式線程池
7、自定義線程池(ThreadPoolExecutor 7個參數(shù))
6、線程池的7個參數(shù)
1、核心線程數(shù)
2、最大線程數(shù)
3、線程存活時間
4、線程存活時間單位
5、工作隊列
6、線程工廠
7、拒絕策略
7、線程池隊列有哪些
1、直接提交隊列(沒有容量,插入一個就會阻塞,執(zhí)行刪除才會喚醒)
2、有界任務隊列(達到隊列最大值,開啟新的線程,否則一直是核心線程,該隊列現(xiàn)進先出,有數(shù)組和鏈表兩種實現(xiàn))
3、無界任務隊列(這種隊列下最大線程數(shù)是無效的,只有核心線程)
4、優(yōu)先任務隊列(特殊的無界隊列,使用平衡二叉樹堆實現(xiàn),排隊時帶有優(yōu)先級)
8、線程池拒絕策略有哪些
1、丟棄任務拋棄異常
2、直接丟棄任務
3、丟棄隊列最前面的任務
4、調用線程(提交任務的線程)直接執(zhí)行此任務
5、new RejectedExecutionHandler() 自定義拒絕策略
9、線程池的關閉
shutdown 當任務隊列為空的時候,才關閉線程池
shutdownnow 直接停止
10、使用無界隊列的線程池會導致內存飆升嗎?
會的,newFixedThreadPool使用了無界的阻塞隊列LinkedBlockingQueue,如果線程獲取一個任務后,任務的執(zhí)行時間比較長,會導致隊列的任務越積越多,導致機器內存使用不停飆升, 最終導致OOM。
11、線程創(chuàng)建的幾種方式
1、繼承Thread,重寫run方法
2、實現(xiàn)Runnable接口創(chuàng)建線程(無返回值)
3、實現(xiàn)Callable接口+Future創(chuàng)建線程(有返回值,可拋出經(jīng)過檢查的異常)
12、Future有什么用
可以對正在執(zhí)行的任務進行維護操作(取消任務、獲取任務執(zhí)行結果、判斷任務是否已完成等)。
13、FutureTask有什么用
1、可取消的異步計算;
2、利用開始和取消計算的方法、查詢計算是否完成的方法和獲取計算結果的方法,此類提供了對Future的基本實現(xiàn);
3、可使用FutureTask包裝Callable或Runnable對象因為FutureTask實現(xiàn)了Runnable,所以可將FutureTask提交給Executor執(zhí)行;
4、僅在計算完成時才能獲取結果;如果計算尚未完成,則阻塞get方法一旦計算完成,就不能再重新開始或取消計算;
14、線程的生命周期(狀態(tài))
- 新建
- 可運行
- 阻塞(處于阻塞狀態(tài)的線程不會占用CPU資源,阻塞IO操作執(zhí)行完,線程可轉換為可運行狀態(tài))
- 等待(執(zhí)行object.wait()或thread.join()變成等待,notify()或加入的線程執(zhí)行完畢會轉為可運行)
- 固定時間等待(不會無限期地等待,如果線程沒有在指定時間內完成操作,自動轉換為可運行)
- 終止狀態(tài)
15、 i++是線程安全的嗎
i++不是原子性操作,執(zhí)行它包括三個操作:讀i的值、i+1、將新值保存到內存。
所以它不是線程安全的。
16、可重入鎖ReentrantLock
可重入:當一個線程獲得一個對象鎖后,再次請求該對象鎖時,可以再次獲得該對象的鎖。
16.1、Synchronized和ReentrantLock的相同
1、都是獨占鎖
2、都是可重入的
16.2、Synchronized和ReentrantLock的不同
1、ReentrantLock是Java層面的實現(xiàn),手動加鎖手動解鎖,synchronized是JVM層面的實現(xiàn)。
2、ReentrantLock可以實現(xiàn)公平和非公平鎖。
3、ReentantLock獲取鎖時,限時等待,配合重試機制更好的解決死鎖
4、ReentrantLock可響應中斷
5.使用synchronized結合Object上的wait和notify方法可以實現(xiàn)線程間的等待通知機制。ReentrantLock結合Condition接口同樣可以實現(xiàn)這個功能。
17、synchronized可重入鎖的實現(xiàn)原理
1、每一個可重入鎖都會關聯(lián)一個線程ID和一個鎖狀態(tài)status。
2、當一個線程請求方法時,會去檢查鎖狀態(tài),
- 如果鎖狀態(tài)是0,代表該鎖沒有被占用,直接進行CAS操作獲取鎖,將線程ID替換成自己的線程ID。
- 如果鎖狀態(tài)不是0,代表有線程在訪問該方法。此時,如果線程ID是自己的線程ID,
– 可重入鎖,將status自增1,然后獲取到該鎖,進而執(zhí)行相應的方法。
– 非重入鎖,進入阻塞隊列等待。
3、釋放鎖時,
- 可重入鎖,每一次退出方法,就會將status減1,直至status的值為0,最后釋放該鎖。
- 非可重入鎖,直接就會釋放該鎖。
Activiti流程引擎
1、Activiti工作流的主要組件
Activity(活動)、workflow(流程)、workItem(工作項)、rule(規(guī)則)、狀態(tài)(state)
2、Activiti工作流有什么優(yōu)勢
1、提供了可視化的方式進行描述和執(zhí)行業(yè)務流程
2、支持業(yè)務邏輯的可重用性和模塊化開發(fā)
3、支持監(jiān)控和追蹤業(yè)務流程
4、擴展性比較好
3、Activiti工作流service有哪些
1、RepositoryService 流程定義和部署對象
2、RuntimeService 執(zhí)行管理,包括流程實例和執(zhí)行對象
3、TaskService 執(zhí)行任務(正在流程中的)
4、HistoryService 歷史管理
5、IdentityService 用戶角色
4、流程實例和執(zhí)行對象的區(qū)別
流程實例:一個流程中,流程實例只有一個
流程對象:按照流程定義的規(guī)則執(zhí)行一次操作,一個流程中執(zhí)行對象可以多個
5、工作流中一個任務完成后,存在多條連線,如何處理
1、使用流程變量
2、當一個任務完成之后,根據(jù)這幾條連線的條件和設置流程變量,例如${流程變量名==’值’},{}符號是布爾類型,判斷走哪條線。
6、Activiti工作流中排他網(wǎng)關和并行網(wǎng)關都能執(zhí)行什么功能
排他網(wǎng)關:分支,通過連線的流程變量,判斷執(zhí)行哪條連線,如果條件不符合,默認離開連線。只執(zhí)行其中一個流程
并行網(wǎng)關:可以同時執(zhí)行多個流程,直到總流程結束??梢詫α鞒踢M行分支和聚合。
7、分配個人任務的三種方式
1、直接給值,在Xxxx.bpmn中指定
2、流程變量${流程變量名}或#{}
3、用監(jiān)聽類指定任務辦理人(setAssgnee)
8、個人任務和組任務的查詢一樣嗎?
1、不一樣
2、都是用TaskService完成
3、個人任務(taskAssgnee),組任務(taskCandidateUser)
4、數(shù)據(jù)庫存放,個人任務:參與,組任務:類型、參與、候選
綜合性問題
1、生產(chǎn)環(huán)境發(fā)生內存泄露怎么排查問題?
- 1、什么是內存泄露
程序在運行過程中,因為某些原因導致不需要的對象,仍然占用jvm內存空間并且無法回收。導致占用內 存越來越大出現(xiàn)OOM。 - 2、內存泄露出現(xiàn)的現(xiàn)象
頻繁FULL GC、內存暫用量過大無法釋放 - 3、怎么定位問題?
是否是內存泄露?老年代逐步增長?Full gc卡頓?年輕代內存一直在高位無法釋放?頻繁full GC?
使用jstat命令查看虛擬機中各個內存的使用情況、GC情況
使用dump工具把內存dump下來,使用MAT工具進行分析。Mat會分析dump文件的內容,給出分析結果,定位到有問題的類,然后找到有問題代碼進行優(yōu)化。
一般情況可是循環(huán)引用、內存對象泄露沒有銷毀、動態(tài)分配內存后沒有釋放、長期持有對象引用、資源未關閉等情況造成的內存泄露