三萬字帶你了解那些年面過的Java八股文

Java基礎

1. String 和StringBuffer 和 StringBuilder的區別?

String 字符串常量
StringBuffer 字符串變量(線程安全)
StringBuilder 字符串變量(非線程安全)

2. sleep() 區間wait()區間有什么區別?

sleep?是Thread中的方法,線程暫停,讓出CPU,但是不釋放鎖🔐
wait()Object中的方法, 調用次方法必須讓當前線程必須擁有此對象的monitor(即鎖),執行之后 線程阻塞,讓出CPU, 同時也釋放鎖🔐; 等待期間不配擁有CPU執行權, 必須調用notify/notifyAll方法喚醒,(notify是隨機喚醒) 喚醒并不意味著里面就會執行,而是還是需要等待分配到CPU才會執行;

3. Object 中有哪些方法?其中clone(),怎么實現一個對象的克隆,Java如何實現深度克隆?

clone是淺拷貝;只克隆了自身對象和對象內實例變量的地址引用,使用它需要實現接口Cloneable;
使用ObjectStream進行深度克隆; 先將對象序列化;然后再反序列化;

public static <T extends Serializable> T deepClone(T t) throws CloneNotSupportedException {// 保存對象為字節數組try {ByteArrayOutputStream bout = new ByteArrayOutputStream();try(ObjectOutputStream out = new ObjectOutputStream(bout)) {out.writeObject(t);}// 從字節數組中讀取克隆對象try(InputStream bin = new ByteArrayInputStream(bout.toByteArray())) {ObjectInputStream in = new ObjectInputStream(bin);return (T)(in.readObject());}}catch (IOException | ClassNotFoundException e){CloneNotSupportedException cloneNotSupportedException = new CloneNotSupportedException();e.initCause(cloneNotSupportedException);throw cloneNotSupportedException;}}

AI生成項目java運行

ThreadLocal相關

4. ThreadLocal作用和實現方式 ?

TL用于保存本地線程的值, 每個Thread都有一個threadLocals屬性,它是一個ThreadLocalMap對象,本質上是一個Entry數組;Entry是k-v結構; 并且是WeakReference弱引用, K存的是?Thread對象,Value是設置的值; 那么每個線程就可以讀自己設置的值了;

ThreadLocal會不會發生內存泄漏?

會發生內存泄漏
ThreadLocalMap使用ThreadLocal的弱引用作為key,如果一個ThreadLocal沒有外部強引用來引用它,那么系統 GC 的時候,這個ThreadLocal勢必會被回收,這樣一來,ThreadLocalMap中就會出現key為null的Entry,就沒有辦法訪問這些key為null的Entry的value,如果當前線程再遲遲不結束的話,這些key為null的Entry的value就會一直存在一條強引用鏈:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永遠無法回收,造成內存泄漏。
其實,ThreadLocalMap的設計中已經考慮到這種情況,也加上了一些防護措施:在ThreadLocal的get(),set(),remove()的時候都會清除線程ThreadLocalMap里所有key為null的value。

  1. 使用static的ThreadLocal,延長了ThreadLocal的生命周期,可能導致的內存泄漏
  2. 分配使用了ThreadLocal又不再調用get(),set(),remove()方法,那么就會導致內存泄漏。

篇幅限制下面就只能給大家展示小冊部分內容了。這份面試筆記包括了:Java面試、Spring、JVM、MyBatis、Redis、MySQL、并發編程、微服務、Linux、Springboot、SpringCloud、MQ、Kafka 面試專題

需要全套面試筆記的【點擊此處即可】即可免費獲取

ThreadLocal為什么使用弱引用?

key是弱引用好歹還可以 GC掉key的對象;強引用則不行
使用弱引用可以多一層保障:弱引用ThreadLocal不會內存泄漏,對應的value在下一次ThreadLocalMap調用set,get,remove的時候會被清除。

5. InheritableThreadLocal作用和實現方式 ?

InheritableThreadLocal基礎?ThreadLocal?; 他跟ThreadLocal區別是 可以傳遞值給子線程; 每個Thread都有一個inheritableThreadLocals屬性, 創建子線程的時候,把把父線程的Entry數組 塞到子線程的Entry數組中; 所以就實現了父子線程的值傳遞; 注意如果Value是一個非基本類型的對象, 父子線程指向的是相同的引用; 子線程如果修改了值,父線程也是會修改的;

6. InheritableThreadLocal所帶來的問題?

線程不安全:?如果說線程本地變量是只讀變量不會受到影響,但是如果是可寫的,那么任意子線程針對本地變量的修改都會影響到主線程的本地變量
線程池中可能失效:?在使用線程池的時候,ITL會完全失效,因為父線程的TLMap是通過Thread的init方法的時候進行賦值給子線程的,而線程池在執行異步任務時可能不再需要創建新的線程了,因此也就不會再傳遞父線程的TLMap給子線程了

7. 如何解決線程池異步值傳遞問題 (transmittable-thread-local)?

阿里開源的transmittable-thread-local可以很好的解決 在線程池情況下,父子線程值傳遞問題;TransmittableThreadLocal繼承了InheritableThreadLocal, 簡單的原理就是TTL 中的holder持有的是當前線程內的所有本地變量,被包裝的run方法執行異步任務之前,會使用replay進行設置父線程里的本地變量給當前子線程,任務執行完畢,會調用restore恢復該子線程原生的本地變量

HashMap ConcurrentHashMap相關

9. HashMap為什么線程不安全

1.在JDK1.7中,當并發執行擴容操作時會造成環形鏈和數據丟失的情況。(鏈表的頭插法 造成環形鏈)
2.在JDK1.8中,在并發執行put操作時會發生數據覆蓋的情況。(元素插入時使用的是尾插法)
HashMap在put的時候,插入的元素超過了容量(由負載因子決定)的范圍就會觸發擴容操作,就是rehash,這個會重新將原數組的內容重新hash到新的擴容數組中,在多線程的環境下,存在同時其他的元素也在進行put操作,如果hash值相同,可能出現同時在同一數組下用鏈表表示,造成閉環,導致在get時會出現死循環,所以HashMap是線程不安全的。

10. HashMap在jdk7和8中的區別
  1. JDK1.7用的是頭插法,而JDK1.8及之后使用的都是尾插法,那么他們為什么要這樣做呢?因為JDK1.7是用單鏈表進行的縱向延伸,當采用頭插法就是能夠提高插入的效率,但是也會容易出現逆序且環形鏈表死循環問題。但是在JDK1.8之后是因為加入了紅黑樹使用尾插法,能夠避免出現逆序且鏈表死循環的問題。
  2. 擴容后數據存儲位置的計算方式也不一樣:1. 在JDK1.7的時候是直接用hash值和需要擴容的二進制數進行&(這里就是為什么擴容的時候為啥一定必須是2的多少次冪的原因所在,因為如果只有2的n次冪的情況時最后一位二進制數才一定是1,這樣能最大程度減少hash碰撞)(hash值 & length-1)
11. HashMap 為啥將鏈表改成紅黑樹?

提高檢索時間,在鏈表長度大于8的時候,將后面的數據存在紅黑樹中,以加快檢索速度。復雜度變成O(logn)

12. ConcurrentHashMap在jdk7和8中的區別?

可以看出JDK1.8版本的ConcurrentHashMap的數據結構已經接近HashMap,相對而言,ConcurrentHashMap只是增加了同步的操作來控制并發,從JDK1.7版本的ReentrantLock+Segment+HashEntry,到JDK1.8版本中synchronized+CAS+HashEntry+紅黑樹,相對而言

  1. JDK1.8的實現降低鎖的粒度,JDK1.7版本鎖的粒度是基于Segment的,包含多個HashEntry,而JDK1.8鎖的粒度就是HashEntry(首節點)
  2. JDK1.8版本的數據結構變得更加簡單,使得操作也更加清晰流暢,因為已經使用synchronized來進行同步,所以不需要分段鎖的概念,也就不需要Segment這種數據結構了,由于粒度的降低,實現的復雜度也增加了
  3. JDK1.8使用紅黑樹來優化鏈表,基于長度很長的鏈表的遍歷是一個很漫長的過程,而紅黑樹的遍歷效率是很快的,代替一定閾值的鏈表,這樣形成一個最佳拍檔
  4. JDK1.8為什么使用內置鎖synchronized來代替重入鎖ReentrantLock; 因為粒度降低了
提到synchronized時候,順便說一下javaSE1.6對鎖的優化?

在JDK1.5中,synchronized是性能低效的。因為這是一個重量級操作,它對性能大的影響是阻塞的是實現,掛起 線程和恢復線程的操作都需要轉入內核態中完成,這些操作給系統的并發性帶來了很大的壓力
javaSE1.6引入了偏向鎖,輕量級鎖(自旋鎖)后,synchronized和ReentrantLock兩者的性能就差不多了
鎖可以升級, 但不能降級. 即:?無鎖 -> 偏向鎖 -> 輕量級鎖 -> 重量級鎖是單向的.

在這里插入圖片描述

偏向鎖

偏向鎖: HotSpot的作者經過研究發現,大多數情況下,鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得;?偏向鎖是四種狀態中最樂觀的一種鎖:從始至終只有一個線程請求某一把鎖。
偏向鎖的獲取:?當一個線程訪問同步塊并成功獲取到鎖時,會在對象頭和棧幀中的鎖記錄字段里存儲鎖偏向的線程ID,以后該線程在進入和退出同步塊時不需要進行CAS操作來加鎖和解鎖,直接進入
偏性鎖的撤銷:?偏向鎖使用了一種等待競爭出現才釋放鎖的機制,所以當其他線程競爭偏向鎖時,持有偏向鎖的線程才會釋放偏向鎖,并將鎖膨脹為輕量級鎖(持有偏向鎖的線程依然存活的時候)

輕量級鎖

多個線程在不同的時間段請求同一把鎖,也就是說沒有鎖競爭。
加鎖:?線程在執行同步塊之前,JVM會先在當前線程的棧楨中創建用于存儲鎖記錄的空間,并將對象頭中的Mark Word復制到鎖記錄中,官方稱為Displaced Mark Word。然后線程嘗試使用CAS將對象頭中的Mark Word替換為指向鎖記錄的指針。如果成功,當前線程獲得鎖,如果失敗,表示其他線程競爭鎖,當前線程便嘗試使用自旋來獲取鎖。
解鎖:輕量級鎖解鎖時, 會使用原子的CAS操作將當前線程的鎖記錄替換回到對象頭, 如果成功, 表示沒有競爭發生; 如果失敗, 表示當前鎖存在競爭, 鎖就會膨脹成重量級鎖.

重量級鎖

Java線程的阻塞以及喚醒,都是依靠操作系統來完成的,這些操作將涉及系統調用,需要從操作系統 的用戶態切換至內核態,其開銷非常之大。

其他優化

鎖粗化:鎖粗化就是將多次連接在一起的加鎖、解鎖操作合并為一次,將多個連續的鎖擴展成為一個范圍更大的鎖
鎖消除:鎖消除即刪除不必要的加鎖操作。根據代碼逃逸技術,如果判斷到一段代碼中,堆上的數據不會逃逸出當前線程, 那么可以認為這段代碼是線程安全的,不必要加鎖

ReentrantLock和synchronized的區別?

在HotSpot虛擬機中, 對象在內存中的布局分為三塊區域: 對象頭, 示例數據和對其填充.
對象頭中包含兩部分: MarkWord 和 類型指針.
在這里插入圖片描述
多線程下synchronized的加鎖就是對同一個對象的對象頭中的MarkWord中的變量進行CAS操作

Synchronized

對于Synchronized來說,它是java語言的關鍵字,是原生語法層面的互斥,需要jvm實現,Synchronized的使用比較方便簡潔,并且由編譯器去保證鎖的加鎖和釋放

  1. 代碼塊同步: 通過使用monitorentermonitorexit指令實現的.
  2. 同步方法:?ACC_SYNCHRONIZED修飾
ReentrantLock

ReenTrantLock的實現是一種自旋鎖,通過循環調用CAS操作來實現加鎖。它的性能比較好也是因為避免了使線程進入內核態的阻塞狀態。

  1. 等待可中斷,持有鎖的線程長期不釋放的時候,正在等待的線程可以選擇放棄等待,這相當于Synchronized來說可以避免出現死鎖的情況。通過lock.lockInterruptibly()來實現這個機制。
  2. 公平鎖,多個線程等待同一個鎖時,必須按照申請鎖的時間順序獲得鎖,Synchronized鎖非公平鎖,ReentrantLock默認的構造函數是創建的非公平鎖,可以通過參數true設為公平鎖,但公平鎖表現的性能不是很好。
  3. 鎖綁定多個條件,一個ReentrantLock對象可以同時綁定對個對象。ReenTrantLock提供了一個Condition(條件)類,用來實現分組喚醒需要喚醒的線程們,而不是像synchronized要么隨機喚醒一個線程要么喚醒全部線程。
13. 為什么重寫equals時候被要求重寫hashCode()?

如果兩個對象相同(即:用 equals 比較返回true),那么它們的 hashCode 值一定要相同
如果兩個對象的 hashCode 相同,它們并不一定相同(即:用 equals 比較返回 false
為了提供程序效率 通常會先進性hashcode的比較,如果不同,則就么有必要equals比較了;

14. 什么時候回發生內存泄露?讓你寫一段內存泄露的代碼你會怎么寫?

我們知道,對象都是有生命周期的,有的長,有的短,如果長生命周期的對象持有短生命周期的引用,就很可能會出現內存泄露

下面給出一個 Java 內存泄漏的典型例子,

	Vector v = new Vector(10);for (int i = 0; i < 100; i++) {Object o = new Object();v.add(o);o = null;}

AI生成項目java運行

在這個例子中,我們循環申請Object對象,并將所申請的對象放入一個 Vector 中,如果我們僅僅釋放引用本身,那么 Vector 仍然引用該對象,所以這個對象對 GC 來說是不可回收的。因此,如果對象加入到Vector 后,還必須從 Vector 中刪除,最簡單的方法就是將 Vector 對象設置為 null。

v = null

ThreadLocal使用不當也可能泄漏

Java內存模型

在共享內存的并發模型里,線程之間共享程序的公共狀態,線程之間通過寫 - 讀內存中的公共狀態來隱式進行通信。Java 的并發采用的是共享內存模型

線程之間的共享變量存儲在主內存(main memory)中,每個線程都有一個私有的本地內存(local memory)
在這里插入圖片描述

Java 內存模型中的 happen-before 是什么?

從 JDK5 開始,java 使用新的 JSR -133 內存模型,提出了 happens-before 的概念
如果一個操作執行的結果需要對另一個操作可見,那么這兩個操作之間必須存在 happens-before 關系這里提到的兩個操作既可以是在一個線程之內,也可以是在不同線程之間

  1. 程序順序規則:一個線程中的每個操作,happens- before 于該線程中的任意后續操作。
  2. 監視器鎖規則:對一個監視器鎖的解鎖,happens- before 于隨后對這個監視器鎖的加鎖。
  3. volatile 變量規則:對一個 volatile 域的寫,happens- before 于任意后續對這個 volatile 域的讀。
  4. 傳遞性:如果 A happens- before B,且 B happens- before C,那么 A happens- before C。

注意,兩個操作之間具有 happens-before 關系,并不意味著前一個操作必須要在后一個操作之前執行!

?篇幅限制下面就只能給大家展示小冊部分內容了。這份面試筆記包括了:Java面試、Spring、JVM、MyBatis、Redis、MySQL、并發編程、微服務、Linux、Springboot、SpringCloud、MQ、Kafka 面試專題

需要全套面試筆記的【點擊此處即可】即可免費獲取

簡單聊聊volatile 的特性?以及內存語義

可見性。對一個 volatile 變量的讀,總是能看到(任意線程)對這個 volatile 變量最后的寫入。
原子性:對任意單個 volatile 變量的讀 / 寫具有原子性,但類似于 volatile++ 這種復合操作不具有原子性。

volatile 寫的內存語義:當寫一個 volatile 變量時,JMM 會把該線程對應的本地內存中的共享變量刷新到主內存
volatile 讀的內存語義:?當讀一個 volatile 變量時,JMM 會把該線程對應的本地內存置為無效。線程接下來將從主內存中讀取共享變量

為了實現 volatile 的內存語義,編譯器在生成字節碼時,會在指令序列中插入內存屏障來禁止特定類型的處理器重排序。?JMM 采取保守策略

在每個 volatile 寫操作的前面插入一個 StoreStore 屏障。
在每個 volatile 寫操作的后面插入一個 StoreLoad 屏障。
在每個 volatile 讀操作的后面插入一個 LoadLoad 屏障。
在每個 volatile 讀操作的后面插入一個 LoadStore 屏障。

通過反編譯可以看到,有volatile變量修飾的遍歷,會有一個lock前綴的指令,lock前綴的指令在多核處理器下會引發了兩件事情

將當前處理器緩存行的數據會寫回到系統內存。
這個寫回內存的操作會引起在其他CPU里緩存了該內存地址的數據無效。

GC垃圾回收

垃圾回收主要是針對 內存區的哪些區域?

主要追對的是 Java堆 和 方法區 ;
java棧、程序計數器、本地方法棧都是線程私有的,線程生就生,線程滅就滅,棧中的棧幀隨著方法的結束也會撤銷,內存自然就跟著回收了。所以這幾個區域的內存分配與回收是確定的,我們不需要管的。但是java堆和方法區則不一樣,我們只有在程序運行期間才知道會創建哪些對象,所以這部分內存的分配和回收都是動態的。一般我們所說的垃圾回收也是針對的這一部分。

垃圾檢查有哪些算法?
  1. 引用計數法 :給一個對象添加引用計數器,每當有個地方引用它,計數器就加1;引用失效就減1。
    好了,問題來了,如果我有兩個對象A和B,互相引用,除此之外,沒有其他任何對象引用它們,實際上這兩個對象已經無法訪問,即是我們說的垃圾對象。但是互相引用,計數不為0,導致無法回收,所以還有另一種方法:
  2. 可達性分析算法:以根集對象為起始點進行搜索,如果有對象不可達的話,即是垃圾對象。這里的根集一般包括java棧中引用的對象、方法區常良池中引用的對象
垃圾回收方法有哪些?
  1. 標記-清除(Mark-sweep):標記清除算法分為兩個階段,標記階段和清除階段。標記階段任務是標記出所有需要回收的對象,清除階段就是清除被標記對象的空間。優缺點:實現簡單,容易產生內存碎片
  2. 復制(Copying)將可用內存劃分為大小相等的兩塊,每次只使用其中的一塊。當進行垃圾回收的時候了,把其中存活對象全部復制到另外一塊中,然后把已使用的內存空間一次清空掉。?優缺點:不容易產生內存碎片;可用內存空間少;存活對象多的話,效率低下。
  3. 標記-整理(Mark-Compact)先標記存活對象,然后把存活對象向一邊移動,然后清理掉端邊界以外的內存?優缺點:不容易產生內存碎片;內存利用率高;存活對象多并且分散的時候,移動次數多,效率低下
  4. 分代收集算法(目前大部分JVM的垃圾收集器所采用的算法)
    年輕代(Young Generation)的回收算法 (回收主要以Copying為主)
    年老代(Old Generation)的回收算法(回收主要以Mark-Compact為主)
什么時候會觸發Full GC

(1)調用System.gc時,系統建議執行Full GC,但是不必然執行
(2)老年代空間不足
(3)方法區(1.8之后改為元空間)空間不足
(4)創建大對象,比如數組,通過Minor GC后,進入老年代的平均大小大于老年代的可用內存
(5)由Eden區、From Space區向To Space區復制時,對象大小大于To Space可用內存,則把該對象轉存到老年代,且老年代的可用內存小于該對象大小。

GC機制簡要說明一下,不同區使用的算法。

年輕代:是所有新對象產生的地方。年輕代被分為3個部分——Enden區和兩個Survivor區(From和to)當Eden區被對象填滿時,就會執行Minor GC。并把所有存活下來的對象轉移到其中一個survivor區(假設為from區)。Minor GC同樣會檢查存活下來的對象,并把它們轉移到另一個survivor區(假設為to區)。這樣在一段時間內,總會有一個空的survivor區。經過多次GC周期后,仍然存活下來的對象會被轉移到年老代內存空間。通常這是在年輕代有資格提升到年老代前通過設定年齡閾值來完成的。需要注意,Survivor的兩個區是對稱的,沒先后關系,from和to是相對的。
年老代:在年輕代中經歷了N次回收后仍然沒有被清除的對象,就會被放到年老代中,可以說他們都是久經沙場而不亡的一代,都是生命周期較長的對象。對于年老代和永久代,就不能再采用像年輕代中那樣搬移騰挪的回收算法,因為那些對于這些回收戰場上的老兵來說是小兒科。通常會在老年代內存被占滿時將會觸發Full GC,回收整個堆內存。
持久代:用于存放靜態文件,比如java類、方法等。持久代對垃圾回收沒有顯著的影響
在這里插入圖片描述

兩個對象循環引用會不會被被GC?

GC里邊在JVM當中是使用的ROOT算法,ROOT算法 也就是根; 只要看這個兩個對象有沒有掛在 根 上, 掛在根上了 就不會被回收; 沒有掛在根上就會回收;

哪些可以算作根節點?
  1. 方法區中的靜態屬性
  2. 方法區的中的常量
  3. 虛擬機中的局部變量
  4. 本地方法棧中JNI
垃圾收集器 G1有什么樣的特性了解嗎? CMS呢?

Cms與G1的優缺點

CMS垃圾回收器:

  1. 初始標記(CMS-initial-mark) ,會導致STW(stop-the-world);
  2. 并發標記(CMS-concurrent-mark),與用戶線程同時運行
  3. 預清理(CMS-concurrent-preclean),與用戶線程同時運行
  4. 可被終止的預清理(CMS-concurrent-abortable-preclean) 與用戶線程同時運行;
  5. 重新標記(CMS-remark) ,會導致STW; 這個階段會導致第二次stop the word,該階段的任務是完成標記整個年老代的所有的存活對象。
    這個階段,重新標記的內存范圍是整個堆,包含_young_gen和_old_gen。為什么要掃描新生代呢,因為對于老年代中的對象,如果被新生代中的對象引用,那么就會被視為存活對象,即使新生代的對象已經不可達了
  6. 并發清除(CMS-concurrent-sweep),與用戶線程同時運行;

CMS垃圾回收器的優化

1.減少重新標記remark階段停頓
一般CMS的GC耗時 80%都在remark階段,如果發現remark階段停頓時間很長,可以嘗試添加該參數:-XX:+CMSScavengeBeforeRemark
在執行remark操作之前先做一次ygc,目的在于減少ygen對oldgen的無效引用,降低remark時的開銷。

G1垃圾回收器

CMS收集器和G1收集器的區別

區別一: 使用范圍不一樣
CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用
G1收集器收集范圍是老年代和新生代。不需要結合其他收集器使用
區別二: STW的時間
CMS收集器以最小的停頓時間為目標的收集器。
G1收集器可預測垃圾回收的停頓時間(建立可預測的停頓時間模型)
區別三: 垃圾碎片
CMS收集器是使用“標記-清除”算法進行的垃圾回收,容易產生內存碎片
G1收集器使用的是“標記-整理”算法,進行了空間整合,降低了內存空間碎片。

Jvm相關

Jvm內存結構簡要說一些,棧里面一般存儲了什么?
Java內存模型簡要描述一下?
類加載機制簡要描述一下?

虛擬機把描述類的數據從Class文件加載到內存,并對數據進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的java類型。類加載和連接的過程都是在運行期間完成的。

類的加載方式

1):本地編譯好的class中直接加載
2):網絡加載:java.net.URLClassLoader可以加載url指定的類
3):從jar、zip等等壓縮文件加載類,自動解析jar文件找到class文件去加載util類
4):從java源代碼文件動態編譯成為class文件

類加載的過程
  1. 類加載的生命周期:加載(Loading)–>驗證(Verification)–>準備(Preparation)–>解析(Resolution)–>初始化(Initialization)–>使用(Using)–>卸載(Unloading)

加載

a)加載階段的工作
i.通過一個類的全限定名來獲取定義此類的二進制字節流。
ii.將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構。
iii.在java堆中生成一個代表這個類的java.lang.Class對象,做為方法區這些數據的訪問入口。
b)加載階段完成之后二進制字節流就按照虛擬機所需的格式存儲在方區去中

驗證

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

準備

準備階段是正式為變量分配內存并設置初始值,這些內存都將在方法區中進行分配,這里的變量僅包括類標量不包括實例變量

解析

解析是虛擬機將常量池的符號引用替換為直接引用的過程。

初始化

初始化階段是執行類構造器()方法的過程

JVM三種預定義類型類加載器

a. Bootstrap ClassLoader/啟動類加載器
主要負責jdk_home/lib目錄下的核心 api 或 -Xbootclasspath 選項指定的jar包裝入工作.
b. Extension ClassLoader/擴展類加載器
主要負責jdk_home/lib/ext目錄下的jar包或 -Djava.ext.dirs 指定目錄下的jar包裝入工作
c. System ClassLoader/系統類加載器
主要負責java -classpath/-Djava.class.path所指的目錄下的類與jar包裝入工作.
d. User Custom ClassLoader/用戶自定義類加載器(java.lang.ClassLoader的子類)
在程序運行期間, 通過java.lang.ClassLoader的子類動態加載class文件, 體現java動態實時類裝入特性.

雙親委派加載

JVM在加載類時默認采用的是雙親委派機制, 先往上 讓上層加載器去加載
在這里插入圖片描述

由不同的類加載器加載的指定類型還是相同的類型嗎(不同)

在Java中,一個類用其完全匹配類名(fully qualified class name)作為標識,這里指的完全匹配類名包括包名和類名。但在JVM中一個類用其全名和一個加載類ClassLoader的實例作為唯一標識,不同類加載器加載的類將被置于不同的命名空間.?所以是不相同的

在代碼中直接調用Class.forName(String name)方法,到底會觸發那個類加載器進行類加載行為?

Class.forName(String name)默認會使用調用類的類加載器來進行類加載

在編寫自定義類加載器時,如果沒有設定父加載器,那么父加載器是?

在不指定父類加載器的情況下,默認采用系統類加載器(AppClassLoader);

編寫自定義類加載器時,一般有哪些注意點?
  1. 一般盡量不要覆寫已有的loadClass(…)方法中的委派邏輯; 這樣做極有可能引起系統默認的類加載器不能正常工作
如何在運行時判斷系統類加載器能加載哪些路徑下的類?

一 是可以直接調用ClassLoader.getSystemClassLoader()或者其他方式獲取到系統類加載器(系統類加載器和擴展類加載器本身都派生自URLClassLoader),調用URLClassLoader中的getURLs()方法可以獲取到
二 是可以直接通過獲取系統屬性java.class.path 來查看當前類路徑上的條目信息 ,?System.getProperty("java.class.path")

在Java的反射中,Class.forName和ClassLoader的區別

ClassLoader就是遵循雙親委派模型最終調用啟動類加載器的類加載器
Class.forName()方法實際上也是調用的CLassLoader來實現的;在這個forName0方法中的第二個參數被默認設置為了true,這個參數代表是否對加載的類進行初始化,設置為true時會類進行初始化,代表會執行類中的靜態代碼塊,以及對靜態變量的賦值等操作。
Class.forName 默認會進行初始化,執行靜態代碼塊;有參數可以設置

?篇幅限制下面就只能給大家展示小冊部分內容了。這份面試筆記包括了:Java面試、Spring、JVM、MyBatis、Redis、MySQL、并發編程、微服務、Linux、Springboot、SpringCloud、MQ、Kafka 面試專題

需要全套面試筆記的【點擊此處即可】即可免費獲取

Java 類加載機制及常見異常
ClassNotFoundException 發生在加載階段

無法找到目標類
通常加載方式 Class.forName / ClassLoader.loadClass ;
導致原因:1、類名拼寫錯誤或者沒有拼寫完整類名
2,沒有導入相應的jar包

ClassNotFoundError 發生在 鏈接 階段

類加載過程有幾個階段
讀取:找到.class文件,讀取
鏈接:校驗讀取的class文件是否符合規范
初始化:載入靜態資源 靜態塊 產生一個Class對象

NoClassDefFoundError 通常在鏈接階段
Exception和Error的區別

首先Exception和Error都是繼承于Throwable 類,在 Java 中只有 Throwable 類型的實例才可以被拋出(throw)或者捕獲(catch),它是異常處理機制的基本組成類型。
Exception是java程序運行中可預料的異常情況,咱們可以獲取到這種異常,并且對這種異常進行業務外的處理。
Error是java程序運行中不可預料的異常情況,這種異常發生以后,會直接導致JVM不可處理或者不可恢復的情況。所以這種異常不可能抓取到,比如OutOfMemoryError、NoClassDefFoundError等。

平時有沒有遇到一些棧溢出或者內存溢出,內存泄露的問題嗎?如何去分析這個問題?

內存泄漏是指對象實例在新建和使用完畢后,仍然被引用,沒能被垃圾回收釋放,一直積累,直到沒有剩余內存可用。如果內存泄露,我們要找出泄露的對象是怎么被GC ROOT引用起來,然后通過引用鏈來具體分析泄露的原因。分析內存泄漏的工具有:Jprofiler,visualvm等。
內存溢出是指當我們新建一個實力對象時,實例對象所需占用的內存空間大于堆的可用空間。
棧(JVM Stack)存放主要是棧幀( 局部變量表, 操作數棧 , 動態鏈接 , 方法出口信息 )的地方。注意區分棧和棧幀:棧里包含棧幀。與線程棧相關的內存異常有兩個:
a)、StackOverflowError(方法調用層次太深,內存不夠新建棧幀)
b)、OutOfMemoryError(線程太多,內存不夠新建線程)
如果出現了內存溢出問題,這往往是程序本生需要的內存大于了我們給虛擬機配置的內存,這種情況下,我們可以采用調大-Xmx來解決這種問題

如果內存猛增,怎么去排查?

通過jstack分析問題
1、利用top名稱查看哪個java進程占用了較多的cpu資源;
2、通過top -Hp pid可以查看該進程下各個線程的cpu使用情況;
3.通過top -Hp命令定位到cpu占用率較高的線程tid之后,繼續使用jstack pid命令查看當前java進程的堆棧狀態
4.然后將剛剛找到的tid轉換成16進制,在 jstack -pid里面的堆棧信息里面找到對應的線程信息

多線程

為什么《阿里巴巴Java開發手冊》強制不允許使用Executor創建線程池

線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險
主要是Executor的一些方法創建的線程池的對了長度都非常大,容易堆積大量的請求,從而導致OOM

ThreadPoolExecutor機制

下面是ThreadPoolExecutor最核心的構造方法參數:
1)corePoolSize核心線程池的大小
2)maximumPoolSize?最大線程池大小,當隊列滿了 就會創建新線程直至最大
3)keepAliveTime?線程池中超過corePoolSize數目的空閑線程最大存活時間;可以allowCoreThreadTimeOut(true)使得核心線程超出有效時間也關閉
4)TimeUnit keepAliveTime的時間單位
5)workQueue阻塞任務隊列
6)threadFactory新建線程工廠,可以自定義工廠
7)RejectedExecutionHandler當提交任務數超過maximumPoolSize+workQueue之和時,任務會交給RejectedExecutionHandler來處理

重點講解

corePoolSize,maximumPoolSize,workQueue三者之間的關系
1)當線程池小于corePoolSize時,新提交的任務會創建一個新線程執行任務,即使線程池中仍有空閑線程。
2)當線程池達到corePoolSize時,新提交的任務將被放在workQueue中,等待線程池中的任務執行完畢
3)當workQueue滿了,并且maximumPoolSize > corePoolSize時,新提交任務會創建新的線程執行任務
4)當提交任務數超過maximumPoolSize,新任務就交給RejectedExecutionHandler來處理
5)當線程池中超過 corePoolSize線程,空閑時間達到keepAliveTime時,關閉空閑線程
6)當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閑時間達到keepAliveTime也將關閉

RejectedExecutionHandler拒絕策略

1、AbortPolicy策略:該策略會直接拋出異常,阻止系統正常工作;
2、CallerRunsPolicy策略:如果線程池的線程數量達到上限,該策略會把任務隊列中的任務放在調用者線程當中運行;
3、DiscardOledestPolicy策略:該策略會丟棄任務隊列中最老的一個任務,也就是當前任務隊列中最先被添加進去的,馬上要被執行的那個任務,并嘗試再次提交;
4、DiscardPolicy策略:該策略會默默丟棄無法處理的任務,不予任何處理。當然使用此策略,業務場景中需允許任務的丟失;

也可以自己擴展RejectedExecutionHandler接口

workQueue任務隊列

  1. 直接提交隊列:設置為SynchronousQueue隊列,提交的任務不會被保存,總是會馬上提交執行
  2. 有界的任務隊列:有界的任務隊列可以使用ArrayBlockingQueue實現
  3. 無界的任務隊列:有界任務隊列可以使用LinkedBlockingQueue實現
  4. 優先任務隊列:優先任務隊列通過PriorityBlockingQueue實現,它其實是一個特殊的無界隊列,PriorityBlockingQueue隊列可以自定義規則根據任務的優先級順序先后執行
線程設置越多越好嗎?設置到什么值比較合理?

CAS實現機制?
內存中value的偏移量 
long valueOffset = Unsafe.getUnsafe().objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}

AI生成項目java運行

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

通過本地方法Unsafe.getUnsafe().objectFieldOffset獲取 值 在內存中的偏移量;然后又通過本地方法unsafe.compareAndSwapInt?去更新數據; 如果內存中的值跟期望中的值一樣則 修改成update;

CAS的ABA問題

如線程1從內存X中取出A,這時候另一個線程2也從內存X中取出A,并且線程2進行了一些操作將內存X中的值變成了B,然后線程2又將內存X中的數據變成A,這時候線程1進行CAS操作發現內存X中仍然是A,然后線程1操作成功。雖然線程1的CAS操作成功,但是整個過程就是有問題的。比如鏈表的頭在變化了兩次后恢復了原值,但是不代表鏈表就沒有變化
所以JAVA中提供了AtomicStampedReference/AtomicMarkableReference來處理會發生ABA問題的場景,主要是在對象中額外再增加一個標記來標識對象是否有過變更

算法

有哪些常用的排序算法?

冒泡算法、選擇排序、插入排序、希爾排序、歸并排序、快速排序

RPC框架 DUBBO

Dubbo缺省協議采用單一長連接和NIO異步通訊
適合于小數據量大并發的服務調用,以及服務消費者機器數遠大于服務提供者機器數的情況

dubbo請求流程
  1. client一個線程調用遠程接口,生成一個唯一的ID(比如一段隨機字符串,UUID等),Dubbo是使用AtomicLong從0開始累計數字的
  2. 將打包的方法調用信息(如調用的接口名稱,方法名稱,參數值列表等),和處理結果的回調對象callback,全部封裝在一起,組成一個對象object
  3. 向專門存放調用信息的全局ConcurrentHashMap里面put(ID, object)
  4. 將ID和打包的方法調用信息封裝成一對象connRequest,使用IoSession.write(connRequest)異步發送出去
  5. 當前線程再使用callback的get()方法試圖獲取遠程返回的結果,在get()內部,則使用synchronized獲取回調對象callback的鎖, 再先檢測是否已經獲取到結果,如果沒有,然后調用callback的wait()方法,釋放callback上的鎖,讓當前線程處于等待狀態。
  6. 服務端接收到請求并處理后,將結果(此結果中包含了前面的ID,即回傳)發送給客戶端,客戶端socket連接上專門監聽消息的線程收到消息,分析結果,取到ID,再從前面的ConcurrentHashMap里面get(ID),從而找到callback,將方法調用結果設置到callback對象里。
  7. 監聽線程接著使用synchronized獲取回調對象callback的鎖(因為前面調用過wait(),那個線程已釋放callback的鎖了),再notifyAll(),喚醒前面處于等待狀態的線程繼續執行(callback的get()方法繼續執行就能拿到調用結果了),至此,整個過程結束。
dubbo 各個模塊?

Service 業務層:業務代碼的接口與實現
config 配置層:對外配置接口,以 ServiceConfig, ReferenceConfig 為中心,可以直接初始化配置類,也可以通過 Spring 解析配置生成配置類。
proxy 服務代理層:服務接口透明代理
registry 注冊中心層:封裝服務地址的注冊與發現
cluster 路由層:封裝多個提供者的路由及負載均衡
monitor 監控層:RPC 調用次數和調用時間監控

如果zookeeper掛掉了,dubbo還能正常運行嗎?

能,本地有保存一份數據;

Dubbo 使用什么通信框架?

在 Dubbo 的最新版本,默認使用 Netty4 的版本
當然你也可以通過SPI 選擇Netty3 Mina Grizzly

Dubbo 支持哪些序列化方式?

【重要】Hessian2 :基于 Hessian 實現的序列化拓展。dubbo:// 協議的默認序列化方案
Dubbo :Dubbo 自己實現的序列化拓展
還有?Kryo 、FST、JSON、NativeJava、CompactedJava

Dubbo 有哪些集群容錯策略?

Failover Cluster[默認]:?失敗自動重試其他服務的策略。
Failover Cluster :?失敗自動切換,當出現失敗,重試其它服務器。通常用于讀操作,但重試會帶來更長延遲。可通過 retries=“2” 來設置重試次數(不含第一次)。
Failfast Cluster:快速失敗,只發起一次調用,失敗立即報錯。通常用于非冪等性的寫操作,比如新增記錄。
Failsafe Cluster:?失敗安全,出現異常時,直接忽略。通常用于寫入審計日志等操作
Failback Cluster:?失敗自動恢復,后臺記錄失敗請求,定時重發。通常用于消息通知操作。
Forking Cluster:?并行調用多個服務器,只要一個成功即返回。通常用于實時性要求較高的讀操作,但需要浪費更多服務資源。可通過 forks=“2” 來設置最大并行數。
Broadcast Cluster:?廣播調用所有提供者,逐個調用,任意一臺報錯則報錯。通常用于通知所有提供者更新緩存或日志等本地資源信息。

Dubbo 服務如何做降級?
  1. Dubbo 原生自帶的服務降級功能
  2. 引入支持服務降級的組件 比如 Alibaba Sentinel
Dubbo 如何做限流?
  1. Dubbo 原生自帶的限流功能,通過 TpsLimitFilter 實現,僅適用于服務提供者
  2. 引入支持限流的組件 例如Sentine

?篇幅限制下面就只能給大家展示小冊部分內容了。這份面試筆記包括了:Java面試、Spring、JVM、MyBatis、Redis、MySQL、并發編程、微服務、Linux、Springboot、SpringCloud、MQ、Kafka 面試專題

需要全套面試筆記的【點擊此處即可】即可免費獲取

如何自己設計一個類似 Dubbo 的 RPC 框架?

舉個栗子,我給大家說個最簡單的回答思路:

  1. 上來你的服務就得去注冊中心注冊吧,你是不是得有個注冊中心,保留各個服務的信心,可以用 zookeeper 來做,對吧。
  2. 然后你的消費者需要去注冊中心拿對應的服務信息吧,對吧,而且每個服務可能會存在于多臺機器上。
  3. 接著你就該發起一次請求了,咋發起?當然是基于動態代理了,你面向接口獲取到一個動態代理,這個動態代理就是接口在本地的一個代理,然后這個代理會找到服務對應的機器地址。
  4. 然后找哪個機器發送請求?那肯定得有個負載均衡算法了,比如最簡單的可以隨機輪詢是不是。
  5. 接著找到一臺機器,就可以跟它發送請求了,第一個問題咋發送?你可以說用?netty?了,nio 方式;第二個問題發送啥格式數據?你可以說用 hessian?序列化協議了,或者是別的,對吧。然后請求過去了。
  6. 服務器那邊一樣的,需要針對你自己的服務生成一個動態代理,監聽某個網絡端口了,然后代理你本地的服務代碼。接收到請求的時候,就調用對應的服務代碼,對吧。
    這就是一個最最基本的 rpc 框架的思路,先不說你有多牛逼的技術功底,哪怕這個最簡單的思路你先給出來行不行?
dubbo SPI 機制 與 JAVA SPI?

Zookeeper

zookeeper快速選舉描述一下?
  1. 每個事務,會分配全局唯一的遞增id(zxid,64位:epoch + 自增 id),每次一個leader被選出來,它都會有一 個新的epoch,標識當前屬于那個leader的統治時期。低32位用于遞增計數

Zookeeper的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫做Zab協議。Zab協議有兩種模式,它們分別是恢復模式(選主)和廣播模式(同步)。當服務啟動或者在領導者崩潰后,Zab就進入了恢復模式,當領導者被選舉出來,且大多數Server完成了和leader的狀態同步以后,恢復模式就結束了。狀態同步保證了leader和Server具有相同的系統狀態。leader選舉是保證分布式數據一致性的關鍵。
當zk集群中的一臺服務器出現以下兩種情況之一時,就會開始leader選舉。
(1)服務器初始化啟動。
(2)服務器運行期間無法和leader保持連接。
而當一臺機器進入leader選舉流程時,當前集群也可能處于以下兩種狀態。
(1)集群中本來就已經存在一個leader。
(2)集群中確實不存在leader。
首先第一種情況,通常是集群中某一臺機器啟動比較晚,在它啟動之前,集群已經正常工作,即已經存在一臺leader服務器。當該機器試圖去選舉leader時,會被告知當前服務器的leader信息,它僅僅需要和leader機器建立連接,并進行狀態同步即可。

開始選舉

sid:即server id,用來標識該機器在集群中的機器序號。
zxid:即zookeeper事務id號。
ZooKeeper狀態的每一次改變, 都對應著一個遞增的Transaction id,,該id稱為zxid.,由于zxid的遞增性質, 如果zxid1小于zxid2,,那么zxid1肯定先于zxid2發生。創建任意節點,或者更新任意節點的數據, 或者刪除任意節點,都會導致Zookeeper狀態發生改變,從而導致zxid的值增加。
以(sid,zxid)的形式來標識一次投票信息。
(1)初始階段,都會給自己投票。
(2)當接收到來自其他服務器的投票時,都需要將別人的投票和自己的投票進行pk,規則如下:
優先檢查zxid。zxid比較大的服務器優先作為leader。如果zxid相同的話,就比較sid,sid比較大的服務器作為leader。

有了解過zk的watch機制嗎?

客戶端watcher 可以監控節點的數據變化以及它子節點的變化,一旦這些狀態發生變化,zooKeeper服務端就會通知所有在這個節點上設置過watcher的客戶端 ,從而每個客戶端都很快感知,它所監聽的節點狀態發生變化,而做出對應的邏輯處理。
watch對節點的監聽事件是一次性的

那你說說Zookeeper有哪些應用場景?
  1. 數據發布與訂閱
  2. 命名服務:作為分布式命名服務,命名服務是指通過指定的名字來獲取資源或者服務的地址,利用ZooKeeper創建一個全局的路徑,這個路徑就可以作為一個名字,指向集群中的集群,提供的服務的地址,或者一個遠程的對象等等。
  3. 配置管理
  4. 集群管理: 所謂集群管理就是:是否有機器退出和加入、選舉master。
  5. 分布式鎖
  6. 分布式隊列:生產者通過在queue節點下創建順序節點來存放數據,消費者通過讀取順序節點來消費數據。
zookeeper實現分布式鎖怎么實現?
  1. 創建臨時順序節點
  2. 判斷自己是不是最小值,是則獲取了鎖
  3. 用watch自己前面的一個節點;如果前面的節點刪除了,則節點收到通知之后,立馬判斷自己是不是最小的節點,如果是則獲取鎖;如果不是,則watch它前面的一個節點
    每個watch只會通知一次,鎖具有順序性,并且watch自己前面的一個節點是為了避免羊群效應
    在這里插入圖片描述
zookeeper集群可以部署2臺嗎?

Redis

redis是單線程還是雙線程?

家所熟知的 Redis 確實是單線程模型,指的是執行 Redis 命令的核心模塊是單線程的,而不是整個 Redis 實例就一個線程,Redis 其他模塊還有各自模塊的線程的。
Redis基于Reactor模式開發了網絡事件處理器,這個處理器被稱為文件事件處理器。它的組成結構為4部分:多個套接字、IO多路復用程序、文件事件分派器、事件處理器。
因為文件事件分派器隊列的消費是單線程的`,所以Redis才叫單線程模型。
在這里插入圖片描述

Redis 不僅僅是單線程

一般來說 Redis 的瓶頸并不在 CPU,而在內存和網絡。如果要使用 CPU 多核,可以搭建多個 Redis 實例來解決。
其實,Redis 4.0 開始就有多線程的概念了,比如 Redis 通過多線程方式在后臺刪除對象、以及通過 Redis 模塊實現的阻塞命令等。

Redis6.0為什么網絡處理要引入多線程?

在這里插入圖片描述

內存不夠的話,可以加內存或者做數據結構優化和其他優化等?但網絡的性能優化才是大頭,網絡 IO 的讀寫在 Redis 整個執行期間占用了大部分的 CPU 時間,如果把網絡處理這部分做成多線程處理方式,那對整個 Redis 的性能會有很大的提升。Redis 的多線程部分只是用來處理網絡數據的讀寫和協議解析,執行命令仍然是單線程

為什么redis的性能高?什么決定的?
  1. 完全基于內存,絕大部分請求是純粹的內存操作,非常快速。
  2. 數據結構簡單,對數據操作也簡單,Redis 中的數據結構是專門進行設計的;
  3. 采用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的性能消耗;(但是redis6.0已經開始使用多線程了,不過是在網絡層面)
  4. 使用多路 I/O 復用模型,非阻塞 IO;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/web/92171.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92171.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92171.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HTML 媒體元素概述

HTML 提供了多種元素用于嵌入和控制多媒體內容&#xff0c;包括音頻、視頻、圖像、畫布等。以下是常用的 HTML 媒體元素及其用法&#xff1a;音頻 (<audio>)<audio> 元素用于嵌入音頻內容&#xff0c;支持 MP3、WAV、OGG 等格式。 示例代碼&#xff1a;<audio c…

http請求結構體解析

copy了一個接口的curl用來說明http請求的三個結構&#xff1a;請求行&#xff0c;請求頭&#xff0c;請求體 文章目錄一、請求的curl報文示例二、解析1. 請求行&#xff08;Request Line&#xff09;2. 請求頭&#xff08;Request Headers&#xff09;3. 請求體&#xff08;Req…

無人機遙控器舵量技術解析

一、舵量的核心作用1. 精確控制的核心 舵量值&#xff08;通常以PWM微秒值表示&#xff09;量化了操作指令的強度&#xff1a; 小舵量&#xff08;1000μs&#xff09;&#xff1a;對應舵機最小角度或電機最低轉速&#xff1b; 中點&#xff08;1500μs&#xff09;&#xf…

Git分支相關命令

在 Git 中&#xff0c;分支管理是非常重要的一部分。下面是一些常用的 Git 分支操作命令及其示例。 1. 查看所有分支 要查看項目中的所有分支&#xff08;包括本地和遠程&#xff09;&#xff0c;可以使用&#xff1a; git branch -a僅查看本地分支&#xff1a;git branch2. 創…

Apache Flink 的詳細介紹

Apache Flink 是一個開源的分布式流處理框架&#xff0c;專注于高吞吐、低延遲、 Exactly-Once 語義的實時數據處理&#xff0c;同時也支持批處理&#xff08;將批數據視為有限流&#xff09;。它廣泛應用于實時數據分析、實時 ETL、監控告警、欺詐檢測等場景&#xff0c;是當前…

Qt 常用控件 - 5

Qt 常用控件 - 4https://blog.csdn.net/Small_entreprene/article/details/149830464 前文補充 QRadioButton&#xff08;單選按鈕&#xff09; QRadioButton 是單選按鈕&#xff0c;允許在多個選項中選擇一個。作為 QAbstractButton 和 QWidget 的子類&#xff0c;前面介紹…

vue的響應式原理

Vue.js 的響應式原理是其核心特性之一&#xff0c;使得數據變化能夠自動更新到視圖。Vue 的響應式系統主要依賴于 Object.defineProperty&#xff08;在 Vue 2.x 中&#xff09;和 Proxy&#xff08;在 Vue 3.x 中&#xff09;來實現數據的觀察和更新。以下是對 Vue 響應式原理…

【AI論文】PixNerd:像素神經場擴散

摘要&#xff1a;擴散變換器目前所取得的成功在很大程度上依賴于預訓練變分自編碼器&#xff08;VAE&#xff09;所塑造的壓縮潛在空間。然而&#xff0c;這種兩階段訓練模式不可避免地會引入累積誤差和解碼偽影。為解決上述問題&#xff0c;研究人員選擇回歸像素空間&#xff…

Java中的LambdaMetafactory:動態生成Lambda的底層黑魔法

引言 在Java 8中&#xff0c;Lambda表達式作為最引人注目的新特性之一被引入。但你是否曾好奇過&#xff0c;這些簡潔的Lambda表達式在底層是如何實現的&#xff1f;這就是LambdaMetafactory發揮作用的地方。作為Java語言中一個不太為人所知但極其重要的類&#xff0c;LambdaMe…

看不見的偽造痕跡:AI時代的鑒偽攻防戰

在生成式人工智能飛速發展的今天&#xff0c;“眼見為實”這句話的有效性正面臨前所未有的挑戰。以往&#xff0c;圖像篡改往往通過傳統的圖像處理工具&#xff08;如 Photoshop&#xff09;進行&#xff0c;需要較高的技術門檻和人工成本&#xff1b;而現在&#xff0c;僅需通…

《React+TypeScript實戰:前端狀態管理的安全架構與性能優化深解》

當用戶在界面上進行表單提交、數據篩選等操作時,每一次交互的精準響應,都依賴于底層狀態架構對風險的預判與性能的調控。深入理解如何在功能實現之外,構筑一套兼顧狀態安全與運行高效的體系,是從基礎開發邁向工程化實踐的關鍵一躍。狀態管理機制的設計,需要穿透“數據更新…

【android bluetooth 協議分析 01】【HCI 層介紹 30】【hci_event和le_meta_event如何上報到btu層】

一、引言 在藍牙協議棧中&#xff0c;HCI Event 和 LE Meta Event 是控制器&#xff08;Controller&#xff09;向主機&#xff08;Host&#xff09;報告事件的兩種形式&#xff0c;它們屬于 HCI&#xff08;Host Controller Interface&#xff09;層。這是主機和控制器之間通…

小實驗--震動點燈

1.實驗目的 使用中斷的方法&#xff0c;震動傳感器檢測到震動時&#xff0c;LED1點亮2秒&#xff0c;之后熄滅。 2.硬件清單 震動傳感器STM32開發板ST-Link 3.硬件連接STM32震動傳感器PA4DO3V3VCCGNDGND4.代碼 4.1exti.c #include "exti.h" #include "sys.h&quo…

vcpkg: 一款免費開源的C++包管理器

目錄 1.簡介 2.安裝 3.常用命令 4.與項目集成 5.vcpkg的工作原理 5.1.包索引&#xff1a;ports 系統&#xff08;定義庫的 “元信息”&#xff09; 5.2.源碼獲取&#xff1a;從 “地址” 到 “本地緩存” 5.3.編譯構建&#xff1a;按 “triplet” 定制目標 5.4.安裝布…

WinCC通過無線Modbus TCP監控S7-1200/200SMT PLC實例詳解

工業自動化系統中&#xff0c;車間內通常部署多臺PLC設備并需通過中央監控平臺實現集中管控。考慮到工業現場設備間距普遍在數十至數百米范圍&#xff0c;傳統有線以太網雖能保障傳輸速率&#xff0c;但其施工需面臨電纜溝開挖或復雜布線工程&#xff0c;既增加線材采購、人力投…

【AI智能編程】Trae-IDE工具學習

什么是Trae&#xff1f; Trae與 AI 深度集成&#xff0c;提供智能問答、代碼自動補全以及基于 Agent 的 AI 自動編程能力。使用 Trae 開發項目時&#xff0c;你可以與 AI 靈活協作&#xff0c;提升開發效率。提供傳統的 IDE 功能&#xff0c;包括代碼編寫、項目管理、插件管理…

智能駕駛再提速!批量蘇州金龍L4級自動駕駛巴士交付杭州臨平區

近日&#xff0c;由蘇州金龍海格客車研發的“清源”L4級自動駕駛巴士現身杭州市臨平區并投入測試。這是臨平區引進的首批L4級自動駕駛巴士&#xff0c;標志著臨平區智能交通建設邁入新階段。此次投入測試的“清源”小巴采用一級踏步設計&#xff0c;車身延續了海格蔚藍巴士的經…

Spring_事務

在mysql階段的文章中&#xff0c;已經介紹過事務了。本篇文章是對mysql事務的總結和對使用Spring框架來實現事務操作的講解。事務回顧什么是事務事務時一組操作的集合&#xff0c;是一個不可分割的操作。事務會把所有操作作為一個整體&#xff0c;一起向數據庫提交或者撤銷操作…

事務管理介紹

為什么要用事務管理在我們同時操作兩個或更多個數據庫時&#xff0c;可能因為網絡等各方面原因導致中間出現異常。造成像對第一個數據庫的操作成功了&#xff0c;但是對第二個數據庫的操作沒有成功。這樣數據的完整性就被破壞了。事務&#xff1a;是一組操作的集合&#xff0c;…

Android 之 ViewBinding 實現更安全、高效的視圖綁定

??一、配置說明????作用位置??需在模塊級 build.gradle或 build.gradle.kts文件的 android {}塊內添加&#xff1a;android {buildFeatures {viewBinding true // Kotlin DSL 語法} }android {buildFeatures {viewBinding true // Groovy 語法} }??生成規則??為每…