40道經典java多線程面試題


40道經典java多線程面試題

題目來源

看完了java並發編程的藝術,自認為多線程“大成”,然后找了一些面試題,也發現了一些不足。

一下問題來源於網上的博客,答案均為本人個人見解,若有疑問或錯誤歡迎討論。QQ:1807812486

1.什么是線程

線程是操作系統能夠進行運算調度的最小單位,它被包含在進程當中,是進程的實際運作單位。

2.線程和進程的區別

一個進程是一個獨立的運行環境,它可以被看做是一個程序或應用。線程是進程中執行的一個任務。線程是進程的子集,一個進程可以有多個線程。進程獨占一片內存,進程共享內存。

3.CyclicBarrier和CountDownLatch有什么不同

CountDownLatch和CyclicBarrier都用於讓線程等待,達到一定條件時再運行。CountDownlatch更加靈活可以在一個線程中多次使用,但是不能重置計數器。CyclicBarrier更加強大,可以重置計數器reset(),可以檢查被阻塞的數目,可以檢查被阻塞的線程是否被中斷。

4.java內存模型是什么(JMM java Memory Model)

java內存模型規定和指引java程序在不同的內存架構,CPU,操作系統中有確定性的行為。JMM定義了線程與主存之間的關系,JMM控制一個線程的共享變量的寫入何時對另一個線程可見。

5.happens-before原則

  • 程序順序規則:一個線程中的任意操作happens-before該線程中的任意后續操作
  • 監視器鎖原則:對於一個鎖的解鎖happens-before該鎖的加鎖。
  • volatile變量原則:volatile寫happens-before volatile讀
  • 傳遞性原則:A happens-before B B happens-before C A happens-before C.

A happens-before B 並不是 A比B先執行,而是A的執行結果對B可見。且 A按順序排在B之前

6.Java中的volatile變量是什么

Volatile是成員變量的修飾符,能夠保證該變量在多線程中的可見性。實現原理是將寫緩存刷新到主存中,然后根據緩存一致性原則保證可見性。

7.什么是線程安全?Vector是一個安全類嗎

在多線程中每一次讀的數據和預期數據一樣就是線程安全(此描述不夠准確)

8.如何實現兩個線程間共享數據

1.通過類變量直接將數據放到主存中
2.通過並發的數據結構來存儲數據
3.使用volatile變量或者鎖
4.調用atomic類

9.為什么wait(),notify(),notifyAll()在對象中,而不在Thread類中

java中鎖的級別是對象級而不是線程級,每個對象都有鎖,通過線程獲得。如果wait()方法在線程中,線程正在等待的是哪個鎖就不明顯了。

10.什么是ThreadLocal變量

ThreadLocal變量是一種特殊的變量,它可以將變量保存副本ThreadLocalMap中供每個線程單獨使用。
ThreadLocal 詳細解析
1.ThreadLocal的結構
  成員變量: threadLocalHashCode   用來區分不同的ThreadLocal
  靜態內部類:ThreadLocalMap       用來存儲ThreadLocal
  方法set(): 通過獲取當前線程t,然后獲得一個threadlocalmap。第一次使用ThreadLocal時會初始化一個ThreadLocalMap,然后復制給當前線程。

11.什么是futureTask

RunnableFuture繼承了Runnable接口和Future接口。它可以取消和啟動一個線程的運行,當調用該類的線程未完成時調用get()會阻塞調用線程,當線程已經完成時會返回結果。futureTask的底層實現原理是AQS 

12.java中interrupt(),interrupted()和isInterrupted()的區別

interrupt()是一個成員方法,調用時會改變中斷狀態,但是不會中斷線程,只有catch后會中斷線程。
interrupted()是一個靜態方法,會中斷線程,中斷狀態為true。
isInterrupted()是一個成員方法,會中斷線程,中斷狀態為false。

	public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

    public boolean isInterrupted() {
        return this.isInterrupted(false);
    }

    private native boolean isInterrupted(boolean var1);
    上面是源碼,也就是說都調用的是本地方法,只是傳入的參數不一樣而已。

13.為什么wait和notify方法要在同步塊中調用?

wait和notify都需要獲得對象鎖

14.為什么你應該在循環中檢查等待條件?

代碼

因為處於等待的線程可能會被假喚醒和錯誤警報,如果不在循環中等待可能會因為沒有滿足條件就退出等待。比如說,退出等待的條件是list()不為空,有7個線程在等待。當list為空時7個都將被喚醒,刪除元素會報錯。

15.同步集合和並發集合有什么不一樣

同步集合的鎖用的是sychronized,比較武斷。並發集合的鎖用的是AQS,靈活性更高,擴展性更強。

16. 有三個線程T1,T2,T3,怎么確保它們按順序執行(確保main()方法所在的線程是Java程序最后結束的線程)?

使用CountDownLatch()和ClclicBarrier方法都可以實現main()方法最后執行。在前一個線程調用后一個線程的join()方法可以按順序執行。

17.如果你提交任務時,線程池隊列已滿。會時發會生什么?

如果coreSize<maxSize 則會創建新的線程來執行任務。如果coreSize=MaxSize 會拋出一個RejectExecutionException.

18.你對線程優先級的理解是什么?

多線程其實是對CPU的輪詢執行,只是CPU處理的速度太快了感覺不到上下文的切換。優先級就是CPU輪詢線程的概率,優先級越高概率越高,優先級越低概率越低。

19.什么是線程池

線程池是管理多線程的一種工具,一個進程可以創建的線程數量是有限的,通過線程池創建的線程執行完成一個任務后不會立即關閉,而是繼續執行阻塞隊列中的線程直到阻塞線程為空。

20.有那些阻塞隊列

ArrayBlockingQueue       一個由數組構成的有界阻塞隊列
LinkedBlockingQueue      一個由鏈表構成的有界阻塞隊列
PriorityBlockingQueue    一個支持優先級排序的無界阻塞隊列
DelayQueue               一個使用優先隊列實現的無界阻塞隊列。
SynchroniouQueue         一個不儲存元素的阻塞隊列
LinkedTransferQueue      一個由鏈表結構組成的無界阻塞隊列
LinkedBlockingDeque      一個由鏈表結構組成的雙向阻塞隊列

21.Java中synchronized 和 ReentrantLock 有什么不同?

synchronized是一個隱式的重入鎖,比較笨重,實現方式是鎖主存和緩存一致性。
reentrantLock是一個顯示的重入鎖,比較靈活,可以擴展為分段鎖,實現方式是AQS.

22.如何避免死鎖?

死鎖發生的條件是
1.存在循環等待
2.存在資源競爭
3.不剝奪條件,已經獲得的資源不會被剝奪
4.請求與保持,一個線程因請求資源被阻塞時,擁有資源的線程的狀態不會改變。
避免死鎖只需要破環其中的一個條件就可以了。

23. 怎么檢測一個線程是否擁有鎖?

Thread中有一個holdLock()方法,當且僅當當前線程擁有某個具體的對象鎖時返回true

24.JVM中哪個參數是用來控制線程的棧堆棧小的

-Xss    

25. Thread類中的yield方法有什么作用?

它會會通知cpu在此處可以更換切片,更不更換由cpu自己決定。(yield可以暫停當前正在執行的線程對象,讓其他有線程執行)

26.Java中ConcurrentHashMap的並發度是什么?

並發度就是segment的個數,通常是2的N次方。默認是16

27.java中的Semaphore是什么

它是一個新的同步類,是一個計數信號。比如在數據庫連接池中,假設我們只能獲得10個數據庫連接,20大小的線程池。此時我們就可以用一個Semaphore來表示數據庫連接池的數目,當需要使用時就accquire()取得許可,使用完畢就release()添加一個許可。

28. 什么是線程調度器(Thread Scheduler)和時間分片(Time Slicing)?

線程調度器是一種操作系統服務,它負責給線程任務分配CPU處理的時間。時間分片指的是CPU一次性處理的一個任務的片段,分配CPU時間可以基於線程優先級或者線程等待時間,但是線程調度並不收到JVM的控制。

29.在多線程中,什么是上下文切換(context-switching)?

上線文切換是指CPU存儲和恢復狀態的過程,它使得線程能夠從中斷狀態恢復繼續運行。

30.如何在Java中創建Immutable對象?

將類和成員變量都設置為final,且成員為私有,成員的初始化通過構造參數初始化。不提供setter()方法。immutable的好處是在沒有同步的情況下是線程安全的。

31. Java中的ReadWriteLock是什么?

它的名稱是讀寫鎖,實現原理是AQS.它將32位的 state狀態變量分為前16位和后16位,前16位狀態表示為讀的狀態,后16位狀態表示為寫的狀態。也就是說讀寫鎖有兩把鎖,一把控制讀,一把控制寫。寫鎖和寫鎖互斥,寫鎖和讀鎖互斥,讀鎖和互鎖相容,寫鎖可以降級為讀鎖。

32.多線程中的忙循環是什么?

忙循環是指程序員用循環來代替wait()方法讓線程進入等待,它的好處是可以占用CPU,不放棄緩存可以減少將數據讀入緩存的時間。

33.volatile 變量和 atomic 變量有什么不同?

volatile的實現方式是將緩存中的值刷新到主存中,本生具有可見性和原子性但是volatile++不具有原子性。
atomic的實現方式是CAS.本質有點類似,也是緩存一致性原則。

34.單例模式的雙檢鎖是什么?

當實例為空時,加鎖再判斷是否為空。如果為空則創建一個新的實例。
安全嗎?不安全
原因:在創建一個對象的時候會分為三個步驟   1.為對象分配內存    2.在內存中初始化一個對象  3.將對象指配給使用者。步驟2依賴於1,所以不會被重排序。步驟3和步驟2沒有依賴可能會被重排序。所以當另外一個線程在此時調用單例可能會獲得一個空的實例。

35.如何在java中創建線程安全的Singleton

1.先加鎖,再判斷。
2.用一個volatile變量進行標識。
3.反射

36. 寫出3條你遵循的多線程最佳實踐

  • 多用同步類,少用wait,notify
  • 少用鎖,應當縮小同步范圍
  • 給線程一個自己的名字
  • 多用並發集合少用同步集合

37.如何強制啟動一個線程?

我覺得沒有方法強制啟動,就像垃圾回收一樣,即使調用了System.gc也不會馬上就gc。因為java中的一個線程和操作系統中的一個線程是一一對應的。操作系統的線程什么時候在cpu上輪詢由操作系統決定,jvm沒有權限就像優先級一樣。

38.java中的fork/join框架是什么

它是jdk7中的一款高效並發編程工具,它利用工作竊取算法將一個大任務划分為若干個子任務,然后將子任務結果合並起來,從而提高了並發編程的效率。

39.線程調度策略?

1.搶占式調度策略
  處於就緒態的線程,根據優先級搶占進入運行態。
2.時間片輪轉調度策略
  所有處於就緒狀態的線程中選擇優先級最高的線程分配一定的CPU時間運行,該時間過后再選擇其他線程運行。

40.在線程中你怎么處理不可捕捉異常?

hread.UncaughtExceptionHandler是java SE5中的新接口,它允許我們在每一個Thread對象上添加一個異常處理器。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM