記一次Java面試問題點總結

来源:https://www.cnblogs.com/zhmlearn/archive/2020/01/20/12201071.html
-Advertisement-
Play Games

引言 昨日接了一個阿裡外包的電話面試,問了一些技術問題感覺到自己是真的菜,接觸Java開發已經也有一段時間,技術方面說來慚愧,一直以來只是局限於框架工具的用法,也沒有進行瞭解其實現的原理,更重要的是一直沒有歸納和總結,這次把這些問題記錄下來,相關的知識點也找了一些資料學習下。 問題 1. Count ...


引言

  昨日接了一個阿裡外包的電話面試,問了一些技術問題感覺到自己是真的菜,接觸Java開發已經也有一段時間,技術方面說來慚愧,一直以來只是局限於框架工具的用法,也沒有進行瞭解其實現的原理,更重要的是一直沒有歸納和總結,這次把這些問題記錄下來,相關的知識點也找了一些資料學習下。

問題

1. CountDownLanch的工作原理

實現原理:計數器的值由構造函數傳入,並用它初始化AQS的state值。當線程調用await方法時會檢查state的值是否為0,如果是就直接返回(即不會阻塞);如果不是,將表示該節點的線程入列,然後將自身阻塞。當其它線程調用countDown方法會將計數器減1,然後判斷計數器的值是否為0,當它為0時,會喚醒隊列中的第一個節點,由於CountDownLatch使用了AQS的共用模式,所以第一個節點被喚醒後又會喚醒第二個節點,以此類推,使得所有因await方法阻塞的線程都能被喚醒而繼續執行。

  引用別人的博客里的一段話,詳細請點擊:Java併發包中CountDownLatch的工作原理、使用示例

題外話: 

什麼是 AQS(抽象的隊列同步器) 
AbstractQueuedSynchronizer類如其名,抽象的隊列式的同步器,AQS定義了一套多線程訪問 共用資源的同步器框架,許多同步類實現都依賴於它,如常用的 ReentrantLock/Semaphore/CountDownLatch。 

 

 

它維護了一個 volatile int state(代表共用資源)和一個 FIFO 線程等待隊列(多線程爭用資源被 阻塞時會進入此隊列)。這裡 volatile 是核心關鍵詞,具體 volatile 的語義,在此不述。state 的 訪問方式有三種: getState() setState()  compareAndSetState()

 

AQS只是一個框架,具體資源的獲取/釋放方式交由自定義同步器去實現,AQS這裡只定義了一個 介面,具體資源的獲取交由自定義同步器去實現了(通過state的get/set/CAS)之所以沒有定義成 abstract,是因為獨占模式下只用實現 tryAcquire-tryRelease,而共用模式下只用實現 tryAcquireShared-tryReleaseShared。如果都定義成abstract,那麼每個模式也要去實現另一模 式下的介面。不同的自定義同步器爭用共用資源的方式也不同。自定義同步器在實現時只需要實 現共用資源 state 的獲取與釋放方式即可,至於具體線程等待隊列的維護(如獲取資源失敗入隊/ 喚醒出隊等),AQS已經在頂層實現好了。自定義同步器實現時主要實現以下幾種方法:
1. isHeldExclusively():該線程是否正在獨占資源。只有用到condition才需要去實現它。

2. tryAcquire(int):獨占方式。嘗試獲取資源,成功則返回true,失敗則返回false。

3. tryRelease(int):獨占方式。嘗試釋放資源,成功則返回true,失敗則返回false。

4. tryAcquireShared(int):共用方式。嘗試獲取資源。負數表示失敗;0 表示成功,但沒有剩餘 可用資源;正數表示成功,且有剩餘資源。

5. tryReleaseShared(int):共用方式。嘗試釋放資源,如果釋放後允許喚醒後續等待結點返回 true,否則返回false。 

AQS定義兩種資源共用方式

1.Exclusive獨占資源 -ReentrantLock Exclusive(獨占,只有一個線程能執行,如ReentrantLock)

2.Share共用資源 -Semaphore/CountDownLatch Share(共用,多個線程可同時執行,如Semaphore/CountDownLatch)。 

3.實現獨占和共用兩種 方式,一般來說,自定義同步器要麼是獨占方法,要麼是共用方式,他們也只需實現 tryAcquiretryRelease、tryAcquireShared-tryReleaseShared 中的一種即可。但 AQS 也支持自定義同步器 同時實現獨占和共用兩種方式,如ReentrantReadWriteLock

 

同步器的實現是ABS核心,以ReentrantLock為例,state初始化為0,表示未鎖定狀態。A線程 lock()時,會調用 tryAcquire()獨占該鎖並將 state+1。此後,其他線程再 tryAcquire()時就會失 敗,直到A線程unlock()到state=0(即釋放鎖)為止,其它線程才有機會獲取該鎖。當然,釋放 鎖之前,A 線程自己是可以重覆獲取此鎖的(state 會累加),這就是可重入的概念。但要註意, 獲取多少次就要釋放多麼次,這樣才能保證state是能回到零態的。 

以CountDownLatch以例,任務分為N個子線程去執行,state也初始化為N(註意N要與 線程個數一致)。這 N 個子線程是並行執行的,每個子線程執行完後 countDown()一次,state 會CAS減1。等到所有子線程都執行完後(即state=0),會unpark()主調用線程,然後主調用線程 就會從await()函數返回,繼續後餘動作。

2. 說一下自旋鎖的原理

如果持有鎖的線程能在很短的時間內釋放鎖資源,那麼那些等待競爭鎖的線程就不需要做內核態和用戶態之間的切換,它們只需要等一等(自旋),等待鎖釋放之後即可立即獲取鎖,這樣避免了用戶線程和內核切換的消耗

線程自旋是需要消耗 cup 的,說白了就是讓 cup 在做無用功,如果一直獲取不到鎖,那線程 也不能一直占用cup自旋做無用功,所以需要設定一個自旋等待的最大時間。
如果持有鎖的線程執行的時間超過自旋等待的最大時間扔沒有釋放鎖,就會導致其它爭用鎖 的線程在最大等待時間內還是獲取不到鎖,這時爭用線程會停止自旋進入阻塞狀態。

自旋鎖的優缺點
自旋鎖儘可能的減少線程的阻塞,這對於鎖的競爭不激烈,且占用鎖時間非常短的代碼塊來 說性能能大幅度的提升,因為自旋的消耗會小於線程阻塞掛起再喚醒的操作的消耗,這些操作會 導致線程發生兩次上下文切換!
但是如果鎖的競爭激烈,或者持有鎖的線程需要長時間占用鎖執行同步塊,這時候就不適合 使用自旋鎖了,因為自旋鎖在獲取鎖前一直都是占用 cpu 做無用功,占著 XX 不 XX,同時有大量 線程在競爭一個鎖,會導致獲取鎖的時間很長,線程自旋的消耗大於線程阻塞掛起操作的消耗, 其它需要cup的線程又不能獲取到cpu,造成cpu的浪費。所以這種情況下我們要關閉自旋鎖;

3. synchronized中類鎖和對象鎖的區別

 這麼基礎的一個問題我竟然遺忘了。。因為之前記的是鎖static方法和非static方法的區別,其實鎖static方法就相當於鎖類class,因為static方法是所有的類共用的,類鎖是鎖當前類的所有實例,對象鎖是鎖當前實例對象,詳細的引入別人的博客:Java鎖Synchronized對象鎖和類鎖的區別

4. volatile關鍵字的作用

     問:說下項目中用到的設計模式

     答:單例模式、責任鏈模式、工程模式、模板模式等等

     問:那你說下你們平常單例模式怎麼實現的

     答:我們用的是雙向檢查

     問:你們雙向檢查有用到volatile吧,那你說下這個關鍵字有什麼作用

     答:它可以用來保證線程每次獲取的對象都是最新狀態

     問:除此之外還有什麼作用

     答: 卒

  真的是

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 上面這張表格實際上是一個n行 6列的二維數組。 多維數組的語法: 註意:每一個中括弧表示一個維度。 習題 設計一個程式,可以保存n年的各科成績,可以對這些年的成績進行查詢。 測試用例:保存3年的成績,查詢第三年的生物成績。 ...
  • 很多人都礙於Python培訓班的高昂費用和有限的空餘時間都選擇自學Python,但是沒有老師幫助,顯得有些迷茫,不知應該從何處學起,也不知識看書學習還是應該看視頻學習。本就來談談這個話題。 ...
  • 一、安裝Docker 1、我是虛擬機裝的Centos7,linux 3.10 內核,docker官方說至少3.8以上,建議3.10以上(ubuntu下要linux內核3.8以上) root賬戶登錄,查看內核版本如下 uname -a 2、把yum包更新到最新 yum update (期間要選擇確認, ...
  • 一.常量 聲明常量可以方便代碼的修改,提高復用性. const int maxn=10000; const int N=10000+10; const double exp=1e-6; 同時,聲明常量也可以減少重覆運算,提高代碼速度,例子如下: string s; cin>>s; for(int i ...
  • 發現一個驗證字元串是否包含中文滴時候,一個比正則更好使滴方法,而且是golang 自帶滴驗證。 不需要自己寫正則驗證,代碼如下: package main import ( "fmt" "regexp" "unicode" ) func main() { s1 := "我是中國人hello word ...
  • 基本構架 所有的C程式都有一個 main 函數.其後包含在大括弧中的是 main 函數的內容. main函數是程式的入口,程式運行後,先進入 main 函數,然後一次執行 main 函數體中的語句. 這是一個例子: 簡單來說,寫在 main 中的內容會在程式啟動時執行.main 函數中的內容是程式的 ...
  • 功能描述:做的是物聯網的項目,Excel導入實現的功能是將Excel中的數據批量的導入AEP系統,再導入我們系統中。目前已經完成該功能,前端還會添加進度條優化。Excel模板: 前端向後端傳遞的參數: 前端代碼: <Upload name="wlwDeviceFile" ref="upload" : ...
  • 導入下列依賴包,搞定 sudo apt-get install python3 python-dev python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev python-pip 上訴 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...