記一次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
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...