Java面試題之并發

并發

    • 1.并發編程的優缺點?
    • 2.并發編程三要素?
    • 3.什么叫指令重排?
    • 4.如何避免指令重排?
    • 5.并發?并行?串行?
    • 6.線程和進程的概念和區別?
    • 7.什么是上下文切換?
    • 8.守護線程和用戶線程的定義?
    • 9.什么是線程死鎖?
    • 10.形成死鎖的四個條件?
    • 11.怎么避免死鎖?
    • 12.創建線程的四種方式?
    • 13.runable和callable區別?
    • 14.run()和start()的區別?
    • 15.什么是futureTask?
    • 16.為什么我們調用start()方法會執行run()方法,為什么我們不能直接調用run()方法?
    • 17.線程生命周期及五種狀態的轉換?
    • 18.線程調度的幾種模型?
    • 19.線程調度策略?
    • 20.什么是線程調度器和時間分片?
    • 21.wait、sleep、yield區別?notify、notifyAll區別?
    • 22.sleep、yield為什么是靜態的?
    • 23.如何調用wait()?使用if塊還是循環塊?
    • 24.為什么線程通信方法wait()、notify()、notifyAll()定義在Object中?
    • 25.為什么wait()、notify()、notifyAll()必須在同步方法或者同步塊中被調用?
    • 26.如何停止一個正在運行的線程?
    • 27.interrupt、interrupted和isInterrupt方法的區別?
    • 28.怎么喚醒阻塞線程?
    • 29.什么是阻塞式方法?
    • 30.實現線程同步的方法?
    • 31.同步方法和同步塊是什么?
    • 32.線程池的工作原理?
    • 33.創建線程池都有哪些方式?
    • 34.線程池常用的幾個參數?
    • 35.線程池的拒絕策略有哪些?
    • 36.線程池都有哪些狀態?
    • 37.線程池中submit()和execute()的區別?
    • 38.當你提交任務時,線程池隊列已滿,這時會發生什么?
    • 39.synchronized使用方式?
    • 40.synchronized的鎖升級的過程
    • 41.synchronized底層原理?
    • 42.什么是自旋?
    • 43.synchronized可重入的原理?
    • 44.synchronized和volicate區別?
    • 45.Lock和synchronized區別?
    • 46.synchronized和ReentrantLock可重入鎖的區別?
    • 47. ReentrantLock是什么?
    • 48.synchronized為什么不能集群操作?如果想集群操作用什么?
    • 49.線程池用完扔回線程池是什么狀態?
    • 50.CAS和ABA的問題?
    • 51.線程池的線程數是怎么確定的?
    • 52.ThredLocal是什么?以及使用場景?
    • 53.什么是臨界區?
    • 53.ab同時提交線程完成任何一個就去執行C,用什么來完成?
    • 54.ab同時提交線程,需要判斷結果,就去執行C,用什么來完成?
    • 55.CountDownLatch是什么?
    • 56.ExecutorService是什么?
    • 55.AQS簡單介紹一下?
    • 55.CLH是什么?
    • 55.線程池的應用場景?
    • 54.為什么要使用并發編程?
    • 55.雙重校驗鎖實現對象單例模式?
    • 56.多線程的應用場景?

1.并發編程的優缺點?

優點

  • 充分利用多核CPU的計算能力,通過并發編程的形式可以將多核CPU的計算能力發揮到極致,性能得到提升;
  • 方便業務拆分,提升系統并發能力和性能;

缺點

  • 內存泄漏;
  • 線程安全問題;
  • 復雜程度增加:比如死鎖;
  • 資源消耗增加:比如頻繁的上下文切換也可能導致額外的性能開銷;

2.并發編程三要素?

  • 原子性:原子,就是一個不可再被分割的顆粒。原子性就是指一個或多個操作要么全部執行成功要么全部執行失敗;
  • 可見性:一個線程對共享變量的修改,另一個線程能夠立刻看到;
  • 有序性:程序執行的順序按照代碼先后順序執行。(處理器可能會對指令進行重排序)

3.什么叫指令重排?

指令重排(也稱為指令重排序)是指在程序執行過程中,指令的執行順序可能與它們在代碼中的順序不一致的現象。編譯器和處理器為了提高程序的執行效率,可能會根據一些規則和優化策略對指令進行重新排序。但是,這種重排序必須保證最終的執行結果與不進行重排時的執行結果保持一致,以確保程序的正確性;存在數據依賴關系的也不允許指令重排

指令重排主要是基于處理器的特性,如多級緩存、多核等,來優化指令的執行順序。這種優化可以使程序在保證業務運行的同時,充分利用CPU的資源,發揮最大的性能。然而,指令重排也可能會導致線程安全問題,特別是在多線程環境下。因此,在編寫并發程序時,需要特別注意指令重排的影響,并采取相應的措施來確保程序的正確性和性能。

4.如何避免指令重排?

  • 使用volatile關鍵字:在Java中,volatile關鍵字可以確保多線程環境下變量的可見性和有序性。當一個變量被聲明為volatile時,它會禁止指令重排,確保所有線程看到的變量值都是一致的。volatile關鍵字還可以防止JVM的指令重排優化,確保代碼的執行順序與預期一致。
  • 使用synchronized關鍵字:synchronized關鍵字可以用來保證代碼塊或方法的原子性,即在同一時刻只能有一個線程執行被保護的代碼。通過synchronized塊或方法,可以確保指令按照預期的順序執行,避免指令重排導致的線程安全問題。
  • 使用Lock接口及其實現類:Java中的Lock接口及其實現類(如ReentrantLock)也可以用來控制并發訪問,保證代碼的正確執行順序。與synchronized相比,Lock接口提供了更靈活的控制方式,可以更好地避免指令重排帶來的問題。
  • 避免使用final關鍵字修飾引用類型變量:在Java中,final關鍵字修飾的引用類型變量在初始化后不能被改變。但是,如果final變量指向的對象是可變的,那么其他線程仍然可以修改該對象的內容。因此,在使用final關鍵字時,需要特別注意避免指令重排導致的線程安全問題。
  • 了解并遵循Happens-Before規則:Happens-Before規則是Java內存模型定義的一組規則,用于確定多線程環境中哪些操作是有序的。遵循這些規則可以確保指令按照預期的順序執行,避免指令重排導致的線程安全問題。

5.并發?并行?串行?

  • 并發:多個任務在同一個cpu上,按細分的時間片輪流執行,從邏輯上來看那些任務是同事執行的;(兩個隊列一臺咖啡機)
  • 并行:單位時間內,多個處理器或多核處理器同時處理多個任務,是真正意義上的同時進行;(兩個隊列一兩臺咖啡機)
  • 串行:有n個任務,由一個線程按順序執行,猶豫任務,方法都在一個線程執行,所以不存在線程不安全情況,也就不存在臨界區的問題;(一個隊列一臺咖啡機)

6.線程和進程的概念和區別?

進程:是操作系統資源分配的基本單位,一個內存中運行的應用程序,每個進程都有自己獨立的一塊內存空間,一個進程可以有多個線程。
線程:處理器任務調度和執行的基本單位,又叫做輕型進程;進程中的一個執行任務,負責當前進程中程序的執行。一個進程至少有一個線程,一個進程可以運行多個線程,多個線程可共享數據;

區別

  • 資源開銷:進程是系統分配資源的基本單位,它擁有獨立的內存空間和系統資源,因此創建和銷毀一個進程需要較大的開銷,包括內存分配、上下文切換等。而線程是進程內的一條執行路徑,多個線程共享同一個進程的內存空間和資源,因此創建和銷毀一個線程的開銷相對較小。
  • 執行方式:進程是獨立執行的,擁有自己的地址空間和資源,相互之間通過進程間通信(IPC)進行交互。而線程是進程內的一條執行路徑,多個線程之間共享進程的資源,因此它們之間的通信和同步更為直接和高效。
  • 并發性:進程在并發執行時具有更高的穩定性,因為每個進程都是獨立的執行單元,擁有自己的調度算法。而線程之間的調度和同步相對復雜,需要更多的注意,以避免出現競態條件、死鎖等問題。
  • 獨立性:進程是獨立的,一個進程出現問題不會影響其他進程的執行。而線程是進程的一部分,一個線程的錯誤可能導致整個進程的崩潰。

7.什么是上下文切換?

CPU采取的策略是為每個線程分配時間片并輪訓的形式,當前任務在執行完CPU時間片切換到另一個任務之前會保存自己的狀態,以便下次再切換回這個任務時,可以再加載這個任務的狀態,任務從保存到再加載過程就是一次上下文切換。

上下文切換消耗大量的CPU時間,可能是操作系統中時間消耗最大的操作。

8.守護線程和用戶線程的定義?

守護線程:運行在后臺,為其他前臺線程服務。也可以說守護線程是JVM中非守護線程的"傭人",一旦所有用戶線程都結束運行,守護線程會隨JVM一起結束工作;

用戶線程:運行在前臺,執行具體任務,如程序的主線程,連接網絡的子線程等都是用戶線程。

守護線程不能依靠finally塊的內容來確保執行關閉或清理資源的邏輯,因為用戶線程結束,守護線程就跟著結束,所以守護線程中的finally語句塊可能無法被執行;

9.什么是線程死鎖?

死鎖是指兩個或兩個以上的進程在執行過程中,由于競爭資源或者由于彼此通信而造成一種阻塞的現象,若無外力作用,他們都將無法推進下去。

10.形成死鎖的四個條件?

  • 互斥條件:線程對于所分配到的資源具有排他性,即一個資源只能被一個線程占用,直到該線程釋放;
  • 請求與保持條件:一個線程因請求被占用資源而發生阻塞時,對已獲得的資源保持不放;
  • 不可剝奪條件:線程已獲得的資源在未使用完之前不能被其他線程強行剝奪,只有自己使用完后才釋放資源;
  • 循環等待條件:當發生死鎖,所等待的線程必定會形成一個環路,造成永久阻塞。

11.怎么避免死鎖?

破壞產生死鎖的四個條件中的其中一個:

  • 破壞互斥條件:
  • 破壞請求與保持條件:
  • 破壞不可剝奪條件:
  • 破壞循環等待條件:

12.創建線程的四種方式?

繼承Thread類

  • 定義一個Thread類的子類,重寫run方法,run方法里就是相關業務邏輯;
  • 創建自定義的線程子類對象;
  • 調用子類實例的start方法啟動線程;

實現runable接口

  • 定義runnable接口實現類MyRunnable,并重新run方法;
  • 創建MyRunnable實例myRunnable,以myRunnable作為target創建Thread對象,該Thread對象才是真正的線程對象;
  • 調用線程對象的start方法;

實現callable接口

  • 創建實現callable接口的類myCallable;
  • 以myCallable為參數創建FutureTask對象;
  • 將FutureTask作為參數創建Thread對象;
  • 調用線程對象的start方法;

使用Excutors工具類創建線程池

Excutors提供了一系列工廠方法用于創建線程池,返回的線程池都實現了ExecutorService接口。

13.runable和callable區別?

相同點

  • 都是接口;
  • 都可以編寫多線程;
  • 都采用Thread.start()啟動線程;

不同點

  • Runnable接口run方法只能拋出異常,不能捕獲異常,沒有返回值;Callable接口call方法有返回值,是個泛型,和Future、FutureTask配合可以用來獲取異步執行的結果;

14.run()和start()的區別?

run()方法稱為線程體,通過調用Thread類的start()方法來啟動一個線程;run()可以重復調用,start()只能調用一次;

15.什么是futureTask?

表示一個異步運算的任務,里面可以傳一個Callable的具體實現類,可以對這個異步運算的任務的結果進行等待獲取、判斷是否已經完成、取消任務等操作。只有當運算完成的時候才能取回結果,如果尚未完成運算,get方法將會阻塞。

16.為什么我們調用start()方法會執行run()方法,為什么我們不能直接調用run()方法?

首先,當你調用一個線程的 start() 方法時,Java虛擬機(JVM)會為這個線程創建一個新的調用棧,并將該線程標記為可運行狀態。然后,JVM會調度這個線程執行,當線程獲得CPU時間片時,就會執行該線程的 run() 方法。這種方式允許線程在操作系統級別進行調度,從而能夠充分利用多核CPU和操作系統提供的線程調度機制,實現真正的并發執行。

而如果你直接調用 run() 方法,那么這個方法就會在當前的調用棧中執行,它只是一個普通的方法調用,并不會啟動一個新的線程。也就是說,run() 方法會在當前線程中同步執行,不會創建新的線程,也就無法實現并發。

因此,start() 方法和 run() 方法的區別在于:start() 方法用于啟動一個新的線程來執行 run() 方法,而 run() 方法本身只是一個普通的方法調用,不會創建新的線程。

17.線程生命周期及五種狀態的轉換?

在這里插入圖片描述

18.線程調度的幾種模型?

  • 分時調度模型:這種模型讓所有線程輪流獲得CPU的使用權,并且平均分配每個線程占用CPU的時間片。這種方式下,每個線程都會得到一定的執行時間,但也可能因為時間片過短而無法完成復雜的任務。
  • 搶占式調度模型:這種模型優先讓可運行池中優先級高的線程占用CPU。如果線程的優先級相同,那么就隨機選擇一個線程使其占用CPU。當線程丟失了CPU的使用權后,再隨機選擇其他線程獲取CPU的使用權。這種方式下,優先級高的線程會獲得更多的執行機會。

需要注意的是,線程的調度不是跨平臺的,它不僅取決于JVM(Java虛擬機),還依賴操作系統。在Java中,搶占式調度模型被采用作為默認的線程調度模型。

19.線程調度策略?

線程調度器選擇優先級最高的線程運行,但是遇到下面幾種情況,就會終止線程的運行:

  • 調用yield方法,讓出cpu的占有權;
  • 調用sleep方法使線程進入睡眠狀態;
  • 另一個更高優先級的線程出現;
  • 在支持時間片的系統中,該線程的時間片用完。

20.什么是線程調度器和時間分片?

線程調度器:是一個操作系統服務,他負責為Runnable狀態的線程分配CPU時間;

時間分片:是指將可用的CPU時間分配給Runnable線程的過程。

21.wait、sleep、yield區別?notify、notifyAll區別?

wait():使一個線程處于等待阻塞狀態,并且釋放所持對象的鎖,Object類的方法,不會自動蘇醒,需要調用notify、notifyAll;
sleep():使一個正在運行的狀態處于睡眠狀態,不釋放鎖,靜態方法,會自動蘇醒,或者等超時后就會自動蘇醒;
yield():由運行狀態變為就緒狀態,靜態方法;
notify():喚醒一個處于等待狀態的線程,并不能確定喚醒哪一個線程,而是與JVM確定喚醒哪個線程,而且與優先級無關,Object類的方法;
notifyAll():喚醒所有處于等待狀態的線程,該方法不是將對象的鎖給所有線程,而是讓他們競爭,只有獲得鎖才能進入就緒狀態,Object類的方法;

22.sleep、yield為什么是靜態的?

sleep()和yield()方法都是Thread類中的靜態方法,這意味著可以直接通過類名來調用它們,而不需要創建Thread類的實例。這兩個方法的行為不依賴于特定線程的狀態或屬性。相反,它們影響的是調用它們的線程本身。因此,將它們設計為靜態方法可以使代碼更加簡潔,并且更符合它們的使用場景。

23.如何調用wait()?使用if塊還是循環塊?

應該在循環塊中調用,因為,當線程獲取到Cpu開始執行的時候,其他條件可能還沒有滿足,所以在處理之前,循環檢測條件是否滿足會更好。

24.為什么線程通信方法wait()、notify()、notifyAll()定義在Object中?

這幾個方法都在同步代碼塊中調用,在java中,任何對象都可以作為鎖,并且wait()、notify()等方法用于等待對象的鎖或者喚醒線程,在Java的線程中并沒有可供對象使用的鎖,所以任意對象調用方法一定定義在Object類中。

25.為什么wait()、notify()、notifyAll()必須在同步方法或者同步塊中被調用?

  • 線程安全性:這些方法的設計初衷是為了實現線程間的安全通信。調用這些方法涉及到線程狀態的改變(例如,從運行狀態變為等待狀態,或從等待狀態變為可運行狀態),以及線程間對共享資源的訪問。為了確保這些操作的原子性和一致性,避免競態條件,它們必須在同步塊或同步方法中調用。

  • 對象鎖wait(), notify(), 和 notifyAll() 方法與對象的內部鎖(也稱為監視器鎖或互斥鎖)緊密相關。當一個線程調用某個對象的 wait() 方法時,它會釋放該對象的鎖,使得其他線程可以獲取這個鎖并執行同步塊或同步方法中的代碼。同樣,當線程調用 notify()notifyAll() 方法時,它會喚醒正在等待該對象鎖的線程,并重新獲取該對象的鎖。這些操作都依賴于對象鎖的存在,因此必須在同步塊或同步方法中執行。

  • 等待/通知機制wait()notify()notifyAll() 方法是等待/通知機制的一部分,該機制允許線程在等待某個條件成立時進入等待狀態,并在條件滿足時被其他線程喚醒。由于這個機制依賴于對象鎖來同步線程間的通信,因此必須在同步塊或同步方法中調用這些方法。

  • 如果這些方法在非同步環境中被調用,會導致 IllegalMonitorStateException 異常,因為調用它們的線程沒有持有對象的鎖,無法安全地執行這些操作。

總的來說,將 wait(), notify(), 和 notifyAll()方法限制在同步方法或同步塊中調用是為了確保線程間的安全通信和正確的同步行為。這是Java語言設計的一部分,旨在防止競態條件和死鎖等并發問題。

26.如何停止一個正在運行的線程?

  • 使用interrupt方法中斷線程;
  • 使用stop方法強行終止,但是不推薦,因為stop已經作廢了;
  • run方法完成后線程終止;

27.interrupt、interrupted和isInterrupt方法的區別?

interrupt:用于中斷線程,線程狀態變為”中斷“狀態;但是線程不會停止,需要用戶自己去監視線程狀態并做處理;

interrupted:是靜態方法,查看當前中斷信號是true還是false并且清除中斷信號,如果一個線程被中斷了,第一次調用interrupted返回true,第二次以后就是fasle了;

isInterrupt:查看當前中斷信號是true還是false;

28.怎么喚醒阻塞線程?

wait、notify方法都是針對對象的,調用wait方法都將導致線程阻塞,阻塞的同時也會釋放該對象的鎖,notify也會喚醒阻塞線程,但是需要重新獲取對象的鎖,才能夠往下執行;
這倆方法必須在synchronized塊或者方法塊中調用,并且保證同步塊或方法的鎖對象與調用wait、notify方法的對象是同一個,如此一來在調用wait之前線程就已經成功獲取某對象的鎖,執行wait阻塞后當前線程就將之前獲取的對象鎖釋放。

29.什么是阻塞式方法?

就是指程序會一直等待該方法完成期間不做其他事情。

30.實現線程同步的方法?

  • 同步代碼方法:synchronized關鍵字修飾的方法;
  • 同步代碼塊:synchronized關鍵字修飾的代碼塊;
  • volatile:為域變量的訪問提供了一種免鎖機制;
  • 使用重入鎖實現線程同步:reentrantlock類是可沖入,互斥,實現了lock接口的鎖;

31.同步方法和同步塊是什么?

  • 同步塊:不會鎖住整個對象,更符合開放調用的原則,只鎖住需要用的代碼塊上,這樣也可以避免死鎖;
  • 同步方法:會鎖住整個對象,哪怕這個類中有多個不相關聯的同步塊,會導致他們停止執行并需要等待獲得這個對象上的鎖。

32.線程池的工作原理?

  • 線程池在創建的時候會創建核心線程數,corepoolsize = 5;
  • 當線程池滿了,不會被立即擴容,而是放到阻塞隊列中,當阻塞隊列滿了之后才會繼續擴容;
  • 如果隊列滿了,線程數達到最大的線程數會執行拒絕策略;
  • 當線程數大于核心線程數,超過了限制時間,線程會被回收,最終保持corepoolsize數;

33.創建線程池都有哪些方式?

手動創建:通過手動編寫代碼來創建線程池,包括創建線程、管理線程的運行以及終止線程等操作。
使用ThreadPoolExecutor類:Java 提供了ThreadPoolExecutor類來簡化線程池的創建和管理,通過該類可以設置線程池的大小、線程池中任務隊列的大小以及拒絕策略等。
使用Executors類:Java提供了Executors類,該類提供了幾個靜態工廠方法,可以根據具體需求來創建不同類型的線程池,如固定大小的線程池、可緩存的線程池、可以執行延遲任務的線程池等。

以下是 Executors 類中常用的幾個線程池方法:

  • newFixedThreadPool(int nThreads)

    創建一個固定大小的線程池,當有新任務提交時,如果線程池中有空閑線程,則立即執行。如果沒有,則新任務會在一個隊列中等待,直到有線程空閑出來。

  • newCachedThreadPool()

    創建一個可緩存的線程池,如果線程池大小超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。這個線程池會對線程進行緩存,如果線程一段時間沒有被使用就會處于空閑狀態,因此它非常適合執行大量的異步任務。

  • newSingleThreadExecutor()

    創建一個單線程的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照提交順序(FIFO)執行。

  • newScheduledThreadPool(int corePoolSize)

    創建一個可以執行定時任務或周期性任務的線程池。核心線程池的大小在創建時設定,當有新任務提交時,如果線程池中有空閑線程,則立即執行。如果沒有,則新任務會在一個隊列中等待,直到有線程空閑出來。這個線程池特別適合需要多個后臺線程執行定時任務或周期性任務的情況。

  • newWorkStealingPool(int parallelism)

    從Java 8開始引入,創建一個支持工作竊取算法的線程池。工作竊取算法是一種提高線程利用率的算法,當某個線程處理完自己的任務后,它會隨機從其他線程的隊列中“竊取”一個任務來執行。這個線程池適合有大量小任務需要執行的情況,可以充分利用多核處理器的優勢。

34.線程池常用的幾個參數?

  • corePoolSize:線程池中的常駐核心線程數。
  • maximumPoolSize:線程池能夠容納同時執行的最大線程數,此值大于等于1。
  • keepAliveTime:多余的空閑線程的存活時間,當空閑時間達到keepAliveTime值時,多余的線程會被銷毀直到只剩下- corePoolSize個線程為止。
  • unit:keepAliveTime的單位。
  • workQueue:任務隊列,被提交但尚未被執行的任務。
  • threadFactory:表示生成線程池中工作線程的線程工廠,用于創建線程,一般用默認的即可。
  • handler:拒絕策略,表示當線程隊列滿了并且工作線程大于等于線程池的最大顯示數(maxnumPoolSize)時如何來拒絕請求執行的runnable的策略。

35.線程池的拒絕策略有哪些?

線程池的拒絕策略是指在線程池已經關閉或達到最大容量時,新提交的任務將被拒絕執行的策略。以下是 Java 線程池中的四種內置拒絕策略:

  • AbortPolicy(默認策略):直接拋出 RejectedExecutionException 異常來阻止系統正常運行。這是線程池默認的拒絕策略。當任務添加到線程池中被拒絕時,它會直接拋出異常。這種策略適用于一些比較重要的業務場景,因為拋出異常可以讓開發者及時發現并處理。

  • CallerRunsPolicy:調用執行自己的線程運行任務。當任務添加到線程池中被拒絕時,不是拋出異常,而是將任務回退到調用者,由調用者所在的線程來執行這個任務。這種策略既不會拋棄任務,也不會拋出異常,而是將某些任務退回,從而降低新任務的流量。

  • DiscardPolicy:不處理,直接丟棄掉。當任務添加到線程池中被拒絕時,線程池會丟棄該任務,且不拋出任何異常。這種策略適用于一些不重要的業務場景,例如統計一些無關緊要但又需要的數據。

  • DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試提交被拒絕的任務。當任務添加到線程池中被拒絕時,線程池會放棄等待隊列中最舊的未處理任務,然后將被拒絕的任務添加到等待隊列中。這種策略可以理解為“殺熟”,即先丟棄最早的任務,以嘗試為新任務騰出空間。

36.線程池都有哪些狀態?

線程池的狀態可以通過ThreadPoolExecutor類的幾個方法查詢,它主要有以下幾種狀態:

  • RUNNING:這是最正常的狀態,表示線程池正在運行,能夠接收新的任務并處理等待隊列中的任務。當線程池被創建后,它就處于RUNNING狀態,此時線程池中的任務數為0。
  • SHUTDOWN:表示線程池不再接收新的任務提交,但會繼續處理等待隊列中的任務。當調用線程池的shutdown()方法時,線程池會由RUNNING狀態轉變為SHUTDOWN狀態。
  • STOP:表示線程池不再接收新的任務提交,并且會中斷正在執行的任務,同時還會中斷正在等待的任務的處理。當調用線程池的shutdownNow()方法時,線程池會由RUNNING或SHUTDOWN狀態轉變為STOP狀態。
  • TIDYING:表示線程池中的所有任務都已經銷毀,workCount為0,線程池的狀態在轉換為TIDYING狀態時,會執行鉤子方法terminated()。當SHUTDOWN狀態下,任務數為0,或者STOP狀態下線程池中執行中任務為空時,線程池會由這些狀態轉變為TIDYING狀態。
  • TERMINATED:表示線程池徹底終止。當線程池在TIDYING狀態下執行完terminated()方法后,就會由TIDYING狀態轉變為TERMINATED狀態。

37.線程池中submit()和execute()的區別?

線程池中的 submit()execute() 方法在功能和使用上存在一些關鍵的區別,主要體現在以下三個方面:

  • 接收的參數不同execute() 方法接收的參數是 Runnable 類型的任務,而 submit() 方法則可以接收 RunnableCallable 類型的任務,這使得 submit() 方法在處理任務時更加靈活。
  • 返回值不同execute() 方法沒有返回值,它僅用于執行給定的任務。這使得我們無法判斷任務是否成功執行或獲取任務的執行結果。相比之下,submit() 方法有返回值,它返回一個 Future 對象,這個對象表示異步計算的結果。通過調用 Future 對象的 get() 方法,我們可以獲取任務的執行結果,并可以在任務完成時處理異常。
  • 異常處理execute() 方法在任務執行過程中拋出異常后,線程會終止,這可能導致線程池中出現無意義的線程,因為線程沒有得到重用。而 submit() 方法在執行過程中不會拋出異常,而是將異常保存在成員變量中。當調用 Future.get() 方法時,如果任務執行過程中有異常發生,get() 方法會拋出異常,這樣我們就可以在外部捕獲并處理這些異常。

總結來說,execute() 方法適用于不需要返回值且不需要處理異常的任務,而 submit()方法則適用于需要返回值或需要處理異常的任務。

38.當你提交任務時,線程池隊列已滿,這時會發生什么?

  • 如果使用的是無界隊列LinkedBlockedQueue,會繼續往里添加等待執行,因為他被認為是一個近乎無窮大的隊列,可以無限存放任務;
  • 如果使用的是有界隊列ArrayBlockedQueue,任務首先會被添加到ArrayBlockedQueue中,如果滿了,會根據maximumPoolSize的值增加線程數量,如果數量處理不過來,滿了,那么會使用拒絕策略,默認是AbortPolicy。

39.synchronized使用方式?

  • 修飾實例方法,鎖的是當前實例對象;
  • 修飾靜態方法,鎖的是當前類的class對象;
  • 修飾代碼塊,同步方法塊鎖的是括號里面的對象;

40.synchronized的鎖升級的過程

synchronized的鎖升級過程主要涉及三種鎖狀態:無鎖狀態、偏向鎖狀態和自旋鎖狀態(輕量級鎖)。以下是具體的升級過程:

  • 無鎖狀態:這是對象的初始狀態,此時沒有線程獲取到鎖。
  • 偏向鎖狀態:當線程首次訪問同步代碼塊并獲取到鎖時,鎖會進入偏向鎖狀態。此時,鎖會記錄下獲取到該鎖的線程ID,以便該線程下次直接獲取鎖,而無需進行CAS操作。這種機制有助于提高程序的性能,因為它避免了不必要的CAS操作。如果線程A已經持有偏向鎖,但尚未執行完同步代碼,此時線程B來請求鎖,會導致CAS失敗,偏向鎖會升級為輕量級鎖。
  • 自旋鎖狀態(輕量級鎖):當偏向鎖升級為輕量級鎖時,如果有其他線程來競爭鎖,那么當前線程會嘗試使用CAS算法獲取鎖。如果獲取成功,則當前線程獲得鎖并執行同步代碼塊。如果獲取失敗,那么當前線程會進行自旋等待,直到獲取到鎖為止。自旋等待的次數是有限制的,當自旋次數達到一定值(默認是10次)時,如果仍未獲取到鎖,那么輕量級鎖會升級為重量級鎖。
  • 重量級鎖:當輕量級鎖升級為重量級鎖時,未獲取到鎖的線程會被阻塞并進入等待狀態,等待操作系統喚醒并重新嘗試獲取鎖。

41.synchronized底層原理?

  • 1.5之前是一個重量級鎖,1.6之后進行了優化;
  • 原子性、可見性、有序性(程序按照代碼先后執行);
  • 通過對象內部一個叫監視器鎖monitor實現的,且每個對象都會有一個與之對應的monitor對象,該對象存儲著當前持有鎖的線程和等待鎖隊列,獲取鎖的時候是monitorenter,釋放鎖的時候是monitorexit,mark word會記錄關于鎖的信息,其加鎖依賴的是操作系統中的互斥指令,有用戶態和內核態的切換性能消耗極為明顯。

42.什么是自旋?

synchronized里面的代碼比較簡單時,執行都比較快,沒必要上鎖,就會在邊界做忙循環,如果多次循環之后還沒獲得鎖,再去阻塞是一種更好的策略。

43.synchronized可重入的原理?

重入鎖是值一個線程獲取到該鎖之后,該線程可以繼續獲得該鎖,底層維護了一個計數器,當線程獲取到該鎖時,計數器+1,再次獲取到該鎖時再+1,釋放鎖時-1,知道為0的時候,釋放鎖。

44.synchronized和volicate區別?

  • synchronized悲觀鎖,屬于搶占式,會引起線程阻塞;
  • volicate提供多線程共享變量可見性和禁止指令重排,當一個共享變量被volicate修飾,會保證修改的值會立即被更新到主存中,當有其他線程需要讀取時,回去內存中讀取新值。

45.Lock和synchronized區別?

  • Lock是個Java類;synchronized是關鍵字;
  • Lock只能給代碼塊加鎖;synchronized可以修飾類、方法、變量;
  • Lock必須手動獲取釋放鎖,synchronized不需要手動來操作;
  • Lock可以知道有沒有獲取鎖成功,synchronized不能做到;
  • Lock可重入、可判斷、可公平;synchronized可重入、不可中斷、非公平;
  • Lock適合有大量同步代碼的同步問題,synchronized適合代碼少量的同步問題;

46.synchronized和ReentrantLock可重入鎖的區別?

  • synchronized是關鍵字;
  • ReentrantLock是一個類,比synchronized更靈活,可以被繼承,可以有方法,但是必須有釋放鎖的動作;
  • ReentrantLock必須手動獲取釋放鎖,synchronized不需要手動來操作;
  • ReentrantLock只適用于代碼塊鎖,synchronized可以修飾類、方法、變量;
  • 二者都是可重入鎖;

47. ReentrantLock是什么?

ReentrantLock的原理基于AQS(AbstractQueuedSynchronizer)框架,它實現了獨占鎖的功能。ReentrantLock通過維護一個內部狀態來表示鎖是否被占用,以及等待獲取鎖的線程隊列。

當一個線程嘗試獲取ReentrantLock時,會調用lock()方法。如果鎖當前沒有被占用(即內部狀態為0),那么該線程會成功獲取鎖,并將內部狀態設置為1。如果鎖已經被其他線程占用,那么該線程會被添加到等待隊列中,進入自旋等待狀態,不斷檢查鎖是否可用。

當一個線程釋放ReentrantLock時,會調用unlock()方法。該方法會將內部狀態減1,表示鎖被釋放。如果此時有等待隊列中的線程在等待獲取鎖,那么會從隊列中取出一個線程來獲取鎖。如果沒有等待的線程,那么鎖就處于可用狀態,等待下一個線程來獲取。

ReentrantLock是一種可重入的互斥鎖,也被稱為“獨占鎖”。它是JDK中的一種線程并發訪問的同步手段,功能類似于synchronized,但提供了比synchronized更強大、靈活的鎖機制,可以減少死鎖發生的概率。ReentrantLock的實現基于AQS(AbstractQueuedSynchronizer)框架,它支持手動加鎖與解鎖,以及加鎖的公平性設置。

ReentrantLock的主要特性包括:

  1. 可重入:ReentrantLock鎖可以被同一個線程多次獲取,只要該線程持有鎖,就可以再次獲取該鎖而不會被阻塞。
  2. 公平性:ReentrantLock支持公平鎖和非公平鎖。在公平鎖機制下,線程會依次排隊獲取鎖,確保先請求的線程先獲取鎖。而在非公平鎖機制下,即使一個線程在隊列的末尾,也有可能在它前面有線程正在持有鎖時獲取到鎖。
  3. 中斷:ReentrantLock支持中斷功能,即當線程在等待獲取鎖的過程中可以被中斷。
  4. 超時:ReentrantLock支持設置超時時間,如果線程在等待獲取鎖的過程中超過了設定的超時時間,那么線程會放棄獲取鎖并繼續執行后續操作。

48.synchronized為什么不能集群操作?如果想集群操作用什么?

synchronized 是 Java 中用于實現線程同步的關鍵字,它保證了同一時刻只有一個線程可以執行被 synchronized 修飾的代碼塊或方法。然而,synchronized 的同步機制是基于 JVM 內部的鎖機制實現的,這意味著它只能保證單個 JVM 進程內的線程同步,而無法跨多個 JVM 進程實現線程同步

在集群環境下實現線程同步,通常需要使用分布式鎖機制。分布式鎖是一種跨多個進程或機器的鎖機制,它可以保證在分布式系統中,同一時刻只有一個節點可以執行某個任務或訪問某個資源。常見的分布式鎖實現方式包括基于數據庫、Redis、ZooKeeper 等的鎖機制。

49.線程池用完扔回線程池是什么狀態?

線程池中的線程在完成任務后,會被放回線程池中,并標記為空閑狀態,等待下一次任務的到來。這種機制使得線程池可以避免頻繁地創建和銷毀線程,減少了系統開銷和內存消耗。

然而,線程池中的線程如果長時間處于空閑狀態,可能會占用系統資源,導致性能下降。因此,線程池通常會設定一個線程的空閑時間閾值,當一個線程在空閑狀態下超過這個閾值后,線程池會判斷該線程不再被需要,從而銷毀該線程,釋放系統資源

50.CAS和ABA的問題?

CAS(Compare-and-Swap)是一種無鎖機制,用于實現多線程之間的同步。CAS操作包含三個操作數——內存位置(V)、期望的原值(A)和新值(B)。執行CAS操作時,會將內存位置V的值與期望的原值A進行比較。如果相匹配,那么處理器會自動將該內存位置V的值更新為新值B。否則,處理器不做任何操作。

ABA問題是指在CAS操作過程中,由于時間差導致數據的變化。具體來說,當多個線程對同一個原子類進行操作時,某個線程將原值A改成了B,然后又改回了A。此時,另一個線程也對該值進行操作,發現它的值仍然是A,就會認為它沒有被修改過,從而執行CAS操作。但實際上,這個值已經被其他線程修改過了,只是最后又被改回了A,這就是ABA問題。

為了解決ABA問題,可以采用版本號或時間戳等機制來標識數據的變化。例如,在Java中,JUC包提供的AtomicStampedReference類和AtomicMarkableReference類就可以解決CAS的ABA問題。AtomicStampedReference類使用一個標記(stamp)來記錄對象的版本號,當對象發生變化時,版本號會自動增加。通過比較對象引用和版本號來判斷對象是否發生過變化,從而避免了ABA問題。AtomicMarkableReference類類似于AtomicStampedReference,但它使用一個布爾標記(mark)來表示對象的狀態是否發生過改變。同樣地,通過比較對象引用和標記來判斷對象是否發生過變化,以避免ABA問題。

51.線程池的線程數是怎么確定的?

CPU密集型任務:這類任務執行大量的計算,但很少進行I/O操作。對于這類任務,線程數量通常設置為CPU核心數加一(Ncpu+1),以減少線程上下文切換的開銷。
I/O密集型任務:這類任務大部分時間都在等待I/O操作完成,如數據庫查詢或網絡請求。對于這類任務,線程數量通常設置為CPU核心數的兩倍(2*Ncpu),甚至更多,以充分利用等待I/O的時間。
混合型任務:在I/O優化中,線程等待時間所占比例越高,需要線程越多,線程CPU時間所占比例越高,需要線程越少。估算公式:最佳線程數=((線程等待時間+線程CPU時間)/線程CPU時間)*CPU數目;

52.ThredLocal是什么?以及使用場景?

ThreadLocal是一個線程變量,它為每個線程創建了一個變量副本,這樣每個線程可以訪問自己內部的副本變量。這意味著ThreadLocal中填充的變量屬于當前線程,并且該變量對其他線程是隔離的,因此可以看作是線程獨有的變量。由于每個線程都有自己的實例副本,并且該副本只能由當前線程使用,因此不存在多線程間共享的問題。

ThreadLocal變量通常被聲明為private static,以便在類的方法中被訪問。總的來說,ThreadLocal提供了一種在多線程環境中管理線程本地數據的方式。

一個線程內可以存在多個ThreadLocal對象,所以其實是ThreadLocal內部維護了一個Map,這個Map不是直接使用的HashMap,而是ThreadLocal實現的一個叫做ThreadLocalMap的靜態內部類。而我們使用的get()、set()方法其實都是調用了這個ThreadLocalMap類對應的get()、set()方法。

ThreadLocal在多種場景中都有應用,主要包括以下幾個方面:

  1. 保存線程獨享的對象:每個線程都可以修改自己所擁有的副本,而不會影響其他線程的副本,確保了線程安全。這特別適用于保存線程不安全的工具類,例如SimpleDateFormat。
  2. 線程間數據隔離:在Web開發中,可以使用ThreadLocal存儲當前請求的上下文信息,避免參數傳遞的復雜性。每個線程在其自己的線程中使用自己的局部變量,各線程間的ThreadLocal對象互不影響。
  3. 數據庫連接管理:ThreadLocal可以為每個線程保持獨立的數據庫連接,提高并發性能。例如,Spring的事務管理器就使用了ThreadLocal來管理數據庫連接。
  4. 日志記錄:ThreadLocal可以將日志記錄與當前線程關聯起來,方便追蹤和排查問題。
  5. 線程池:在線程池中,可以使用ThreadLocal為每個線程維護獨立的上下文信息,避免線程間互相干擾。
  6. AOP緩存:在AOP中,可以將數據緩存到ThreadLocal中,以便在后續的控制器層中獲取到當前變量。

總的來說,ThreadLocal適用于多線程的情況下,可以實現數據傳遞和線程隔離。通過正確使用ThreadLocal,可以提高程序的線程安全性和性能。然而,也需要避免內存泄漏等問題。

53.什么是臨界區?

用來表示一種公共資源或者說是共享資源,可以被多個線程使用,但每個線程使用時,一旦臨界資源被一個線程占用,其他線程必須等待。

53.ab同時提交線程完成任何一個就去執行C,用什么來完成?

這個場景是在考察對Java并發編程中的線程管理和線程同步的理解。具體來說,它涉及到以下幾個關鍵點:

  1. Callable和Future的使用

    • Callable 是Java中的一個接口,它允許你定義一個返回結果的任務。Callable 的實例可以被提交給 ExecutorService 去執行,并返回一個 Future 對象。
    • Future 對象代表了異步計算的結果。你可以通過 Future 對象來獲取異步計算的結果,或者檢查計算是否已經完成。
  2. 線程同步

    • 在這個場景中,你需要確保當A或B中的任何一個線程完成時,C線程可以開始執行。這通常涉及到線程同步機制,比如使用 CountDownLatchCyclicBarrierSemaphore 等。
    • CountDownLatch 是一個計數器,允許一個或多個線程等待其他線程完成操作。在這個案例中,你可以設置一個 CountDownLatch 的初始計數為2,然后每個線程A和B在完成任務后調用 countDown() 方法,C線程在 await() 方法上等待,直到計數減到0。
  3. 線程池的使用

    • 為了有效地管理線程,通常會使用 ExecutorService 來創建一個線程池。線程池可以復用線程,減少線程創建和銷毀的開銷。
  4. 異常處理

    • 在使用 CallableFuture 時,需要注意異常處理。如果 Callable 任務拋出異常,它將被封裝在一個 ExecutionException 中,可以通過 Future.get() 方法拋出。
  5. 資源釋放

    • 在使用完 ExecutorService 后,需要調用 shutdown()shutdownNow() 方法來關閉線程池,釋放資源。

54.ab同時提交線程,需要判斷結果,就去執行C,用什么來完成?

可以使用Future和ExecutorService。同時,為了實現輪詢(polling)以檢查任務是否完成,你可以使用一個循環來定期檢查Future的完成狀態。

55.CountDownLatch是什么?

countDown() 是 CountDownLatch 類中的一個方法。CountDownLatch 是一個在 Java 中常用的同步工具類,它允許一個或多個線程等待其他線程完成操作。CountDownLatch 維護了一個內部計數器,該計數器的初始值在創建 CountDownLatch 對象時設定。

countDown() 方法會將這個計數器的值減一。如果計數器的當前值為正數,那么調用 countDown() 后,計數器的值會減一;如果計數器的當前值為零,那么 countDown() 調用將沒有任何效果。

CountDownLatch 的另一個關鍵方法是 await(),它會讓當前線程等待,直到計數器的值減為零。當計數器的值減為零時,所有在 await() 方法上等待的線程將被喚醒并繼續執行。

CountDownLatch 通常用于控制并發線程的執行順序。例如,如果你有一個任務需要多個線程共同完成,并且只有當所有線程都完成它們的工作后,主線程才能繼續執行,那么你可以使用 CountDownLatch 來實現這個需求。每個工作線程在完成自己的任務后,調用 countDown() 方法,而主線程在調用 await() 方法后等待所有工作線程完成。

56.ExecutorService是什么?

ExecutorService是Java中的一個線程池服務,它是Executor的直接擴展接口,也是最常用的線程池接口。線程池是一種用于處理大量短小任務的機制,它避免了頻繁創建和銷毀線程所帶來的開銷,提高了系統的響應速度和資源利用率。

ExecutorService提供了靈活的線程池管理功能,包括控制最大并發線程數、定時執行、定期執行、單線程執行、并發數控制等。當我們有任務需要多線程來完成時,可以將任務(實現Runnable接口、Callable接口或繼承Thread類的對象)提交給ExecutorService來執行。ExecutorService會負責線程的創建、管理和調度,從而簡化了多線程編程的復雜性。

在服務器應用程序中,ExecutorService常用于處理來自遠程來源的大量短小任務。通過將任務提交給線程池來執行,可以避免頻繁創建和銷毀線程所帶來的開銷,提高了服務器的性能。同時,ExecutorService還提供了線程池的關閉和資源釋放功能,以確保資源的正確管理。

55.AQS簡單介紹一下?

AQS,全稱為AbstractQueuedSynchronizer,是一個抽象的隊列式同步器,是Java并發編程中的核心組件。它定義了實現線程同步器的基礎框架,主要用于協調多個線程對共享資源的訪問。

AQS通過維護一個內部狀態(state)來表示同步狀態,這個狀態是一個整數。當state大于0時,表示已經獲取了鎖;當state等于0時,表示鎖已經被釋放。AQS通過原子操作來更新這個狀態,以確保線程安全。

AQS的核心思想是將請求共享資源的線程封裝成一個節點(Node),并將這些節點加入到一個FIFO(先進先出)的隊列中。當共享資源空閑時,將隊列中的第一個節點設置為有效的工作線程,并將共享資源設置為鎖定狀態。如果共享資源被占用,那么線程會阻塞等待,直到獲取到鎖為止。這種機制是通過CLH隊列鎖實現的。

AQS提供了兩種鎖機制:獨占鎖和共享鎖。獨占鎖用于多個線程競爭同一個共享資源的情況,同一時刻只允許一個線程訪問該資源。例如,ReentrantLock就是一個基于AQS實現的獨占鎖。共享鎖則允許多個線程同時訪問共享資源,如CountDownLatch和Semaphore就是基于AQS實現的共享鎖。

此外,AQS還支持公平鎖和非公平鎖。公平鎖按照線程請求鎖的順序來分配鎖,而非公平鎖則允許線程搶占已經持有的鎖。這種機制是通過在AQS中維護一個FIFO隊列來實現的,隊列中的節點按照線程請求鎖的順序排列。

55.CLH是什么?

CLH隊列,全稱是Craig,Landin,和Haqersten提出的鎖隊列,是一個FIFO(先進先出)的雙向鏈表隊列,用于存儲被阻塞的線程信息。它是AQS(AbstractQueuedSynchronizer)內部維護的一個關鍵組件,用來實現線程之間的公平鎖。

當一個線程嘗試獲取同步狀態失敗時,它會被封裝成一個Node節點,并通過CAS原子操作插入到CLH隊列的尾部。此時,該線程會被阻塞。當線程釋放同步狀態后,會喚醒當前節點的next節點,這個next節點會嘗試搶占同步資源。如果搶占失敗,它會重新阻塞;如果成功,它會將自己設置為當前線程的節點,并將之前的head節點廢棄。

CLH隊列具有以下優點:

  1. 先進先出的特性保證了公平性。
  2. 它是一個非阻塞的隊列,通過自旋鎖和CAS保證了節點插入和移除的原子性,實現了無鎖快速插入。因此,CLH隊列也是一種基于鏈表的可擴展、高性能、公平的自旋鎖。

55.線程池的應用場景?

54.為什么要使用并發編程?

55.雙重校驗鎖實現對象單例模式?

56.多線程的應用場景?

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

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

相關文章

<網絡安全>《60 概念講解<第七課 網絡模型OSI對應協議>》

1 OSI模型 OSI模型(Open Systems Interconnection Model)是一個由國際標準化組織(ISO)提出的概念模型,用于描述和標準化電信或計算系統的通信功能,以實現不同通信系統之間的互操作性。該模型將通信系統劃分…

【k8s管理--Helm包管理器】

1、Helm的概念 Kubernetes包管器 Helm是查找、分享和使用軟件構件Kubernetes的最優方式。 Helm管理名為chart的Kubernetes包的工具。Helm可以做以下的事情: 從頭開始創建新的chat將chart打包成歸檔tgz)文件與存儲chat的倉庫進行交互在現有的Kubernetes集群中安裝和…

【Android】View 的滑動

View 的滑動是 Android 實現自定義控件的基礎,同時在開發中我們也難免會遇到 View 的滑動處理。其實不管是哪種滑動方式,其基本思想都是類似的:當點擊事件傳到 View 時,系統記下觸摸點的坐標,手指移動時系統記下移動后…

【AI+應用】怎么快速制作一個類chatGPT套殼網站

最近有人問我, 看了我之前寫的一篇文章 [人工智能] AI浪潮下Sora對于普通人的機會 , 怎么做一個類chatGPT的套殼網站,是從0開始做么。 對于普通人來說,萬事不懂先AI, AI找不到答案搜索google或百度。對于程序員來說…

C# 獲取類型 Type.GetType()

背景 C#是強類型語言,任何對象都有Type,有時候需要使用Type來進行反射、序列化、篩選等,獲取Type有Type.GetType, typeof(),object.GetType() 等方法,本文重點介紹Type.GetType()。 系統類型/本程序集內的類型 對于系…

有哪些視頻媒體?邀請視頻媒體報道活動的好處

傳媒如春雨,潤物細無聲,大家好,我是51媒體網胡老師。 視頻媒體在當今的媒體生態中占據了重要的地位。以下是一些主要的視頻媒體類型: 電視臺:如中央電視臺、各省級衛視臺、地方電視臺等,他們擁有專業的視…

學習linux從0到初級工程師-3

一、LNMP 1.1 搭建LNMP LNMP:LinuxNginxMysqlPHP LNMP優勢: 1.web服務器一種,Nginx處理靜態文件、索引文件,自動索引的效率非常高; 2.作為代理服務器,Nginx可以實現無緩存的反向代理加速,提高網站運行…

探索Redis 6.0的新特性

Redis(Remote Dictionary Server)是一個開源的內存中數據結構存儲系統,通常被用作緩存、消息隊列和實時數據處理等場景。它的簡單性、高性能以及豐富的數據結構支持使其成為了眾多開發者和企業的首選。在Redis 6.0版本中,引入了一…

Vue3報錯Promise executor functions should not be async.

解決方法 加注釋。。。// eslint-disable-next-line no-async-promise-executor // eslint-disable-next-line no-async-promise-executor new Promise<boolean>(async (resolve, reject) > {... }),

Ubuntu綁定USB接口到固定端口

綁定端口 打開終端&#xff0c;輸入以下命令查看USB端口信息&#xff1a; udevadm info -a -n /dev/ttyUSB0執行后&#xff0c;可以看到部分輸出如下: 找到第一個&#xff0c;a-b:c格式的KERNELS&#xff0c;記住這個值&#xff0c;后面會用到。 linlin-B660M-D2H-DDR4:~$ u…

【深藍學院】移動機器人運動規劃--第7章 集群機器人運動規劃--筆記

文章目錄 0. Contents1. Multi-Agent Path Finding (MAPF)1.1 HCA*1.2 Single-Agent A*1.3 ID1.4 M*1.5 Conflict-Based Search(CBS)1.6 ECBS1.6.1 heuristics1.6.2 Focal Search 2. Velocity Obstacle (VO&#xff0c;速度障礙物)2.1 VO2.2. RVO2.3 ORCA 3. Flocking model&am…

【每日前端面經】2023-02-29

題目來源: 牛客 如何理解前端這個崗位 簡單地說就是設計師做好網頁效果圖&#xff0c;前端將效果圖轉化成頁面&#xff0c;之后交給后端程序員&#xff0c;中間的這段工作就是前端 瀏覽器如何渲染HTML 將載入的HTML文件解析成DOM樹&#xff0c;并且將各個標記標識解析成DOM…

SQL的窗口函數

SQL的窗口函數 文章目錄 SQL的窗口函數1. 介紹2. 聚合函數0.數據準備1. AVG2. COUNT3. MAX4. MIN5. 標準差6. SUM 3. 排序函數1. CUME_DIST2. RANK, DENSE_RANK, ROW_NUMBER3. PERCENT_RANK4. NTILE 4. 值函數(偏移函數)1. FIRST_VALUE2. LAST_VALUE3. LAG4. LEAD5. NTH_VALUE …

ChatGPT4.0 的優勢、升級 4.0 為什么這么難以及如何進行升級?

前言 “ChatGPT4.0一個月多少人民幣&#xff1f;” ”chatgpt4賬號“ ”chatgpt4 價格“ “chatgpt4多少錢” 最近發現很多小伙伴很想知道關于ChatGPT4.0的事情&#xff0c;于是寫了這篇帖子&#xff0c;幫大家分析一下。 一、ChatGPT4.0 的優勢 &#xff08;PS&#xff1a;…

LINUX基礎培訓二十七之shell標準輸入、輸出、錯誤

一、Shell 輸入/輸出重定向 大多數 UNIX 系統命令從你的終端接受輸入并將所產生的輸出發送回??到您的終端。一個命令通常從一個叫標準輸入的地方讀取輸入&#xff0c;默認情況下&#xff0c;這恰好是你的終端。同樣&#xff0c;一個命令通常將其輸出寫入到標準輸出&#xff…

【樹莓派系統配置+python3.8+環境配置踩坑點匯總】raspberrypi

最近又開始搞樹莓派的深度學習模型。很多windows端的環境需要在樹莓派上重新部署&#xff0c;中間出現了非常多的問題。主要以各種庫的下載安裝為主要。 首先&#xff0c;第一個問題&#xff1a; 樹莓派系統燒錄之后&#xff0c;默認apt一般需要升級看&#xff0c;而默認下載…

無窮級數法求Π

任務描述 本關任務&#xff1a;編寫一個無窮級數法計算圓周率的小程序。 相關知識 為了完成本關任務&#xff0c;你需要掌握&#xff1a; 無窮級數法 無窮級數法 π 是個超越數&#xff0c;圓周率的超越性否定了化圓為方這種尺規作圖精確求解問題的可能性。有趣的是&…

【Spring】18 Bean 定義繼承

文章目錄 介紹聲明式配置抽象Bean定義繼承的配置項注意&#xff1a;抽象Bean預實例化結論 Spring 框架提供了一個強大的功能&#xff0c;稱為 Bean 定義繼承&#xff0c; 允許開發人員高效地在 bean 之間重用和自定義配置。在本篇文章中我們將介紹 Bean 定義繼承的概念&#x…

JVM性能優化

運行時優化 方法內聯 方法內聯&#xff0c;是指 JVM在運行時將調用次數達到一定閾值的方法調用替換為方法體本身 &#xff0c;從而消除調用成本&#xff0c;并為接下來進一步的代碼性能優化提供基礎&#xff0c;是JVM的一個重要優化手段之一。 注&#xff1a; C的inline屬于編…

babylonsjs入門-基礎模版

基于babylonjs封裝的一些功能和插件 &#xff0c;希望有更多的小伙伴一起玩babylonjs&#xff1b; 歡迎加群&#xff08;點擊群號傳送&#xff09;&#xff1a;464146715 官方文檔 中文文檔 案例傳送門 ? 懶得打字&#xff0c;你們直接去copy組件吧&#xff0c;主要看這2…