面試常見基礎題整理

線程和進程區別和聯繫,什麼是“線程安全”

簡而言之,一個程序至少有一個進程,一個進程至少有一個線程. 
線程的劃分尺度小於進程,使得多線程程序的併發性高。
另外,進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大地提高了程序的運行效率。
線程在執行過程中與進程還是有區別的。每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分可以同時執行。但操作系統並沒有將多個線程看做多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。

進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位.
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.
一個線程可以創建和撤銷另一個線程;同一個進程中的多個線程之間可以併發執行.

如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的  


2. static在C和C++裏各代表什麼含義 

靜態變量或靜態函數只有本文件內的代碼才能訪問它,它的名字在其它文件中不可見。
用法1:函數內部聲明的static變量,可作爲對象間的一種通信機制
    如果一局部變量被聲明爲static,那麼將只有唯一的一個靜態分配的對象,它被用於在該函數的所有調用中表示這個變量。這個對象將只在執行線程第一次到達它的定義使初始化。
用法2:局部靜態對象
    對於局部靜態對象,構造函數是在控制線程第一次通過該對象的定義時調用。在程序結束時,局部靜態對象的析構函數將按照他們被構造的相反順序逐一調用,沒有規定確切時間。
 用法3:靜態成員和靜態成員函數
  如果一個變量是類的一部分,但卻不是該類的各個對象的一部分,它就被成爲是一個static靜態成員。一個static成員只有唯一的一份副本,而不像常規的非static成員那樣在每個對象裏各有一份副本。同理,一個需要訪問類成員,而不需要針對特定對象去調用的函數,也被稱爲一個static成員函數。
類的靜態成員函數只能訪問類的靜態成員(變量或函數)。


3.notify()和notifyAll()的區別

           notify()和notifyAll()都是Object對象用於通知等待該對象的線程(即調用了object.wait()方法的線程)的方法。兩者的最大區別在於:
notifyAll使所有原來在該對象上等待被notify的線程統統退出wait的狀態,
變成等待該對象上的鎖,一旦該對象被解鎖,他們就會去競爭。


         notify則文明得多,他只是選擇一個wait狀態線程進行通知,並使它獲得該對象上的鎖,但不驚動其他同樣在等待被該對象notify的線程們,當第一個線程運行完畢以後釋放對象上的鎖此時如果該對象沒有再次使用notify語句,則即便該對象已經空閒,其他wait狀態等待的線程由於沒有得到該對象的通知,繼續處在wait狀態,直到這個對象發出一個notify或notifyAll,它們等待的是被notify或notifyAll,而不是鎖。

當一個線程進入wait之後,就必須等其他線程notify/notifyall,使用notifyall,可以喚醒
所有處於wait狀態的線程,使其重新進入鎖的爭奪隊列中,而notify只能喚醒一個。注意,任何時候只有一個線程可以獲得鎖,也就是說只有一個線程可以運行synchronized 中的代碼,notifyall只是讓處於wait的線程重新擁有鎖的爭奪權,但是隻會有一個獲得鎖並執行。


4. 軟鏈接與硬鏈接 

Linux/Unix 檔案系統中,有所謂的連結(link),我們可以將其視爲檔案的別名,而連結又可分爲兩種 : 硬連結(hard link)與軟連結(symbolic link),硬連結的意思是一個檔案可以有多個名稱,而軟連結的方式則是產生一個特殊的檔案,該檔案的內容是指向另一個檔案的位置。硬連結是存在同一個檔案系統中,而軟連結卻可以跨越不同的檔案系統。 


5.什麼時候拋出 InvalidMonitorStateException 異常,爲什麼? 

        調用 wait ()/notify ()/notifyAll ()中的任何一個方法時,如果當前線程沒有獲得該對象的鎖,那麼就會拋出 IllegalMonitorStateException 的異常(也就是說程序在沒有執行對象的任何同步塊或者同步方法時,仍然嘗試調用 wait ()/notify ()/notifyAll ()時)。由於該異常是 RuntimeExcpetion 的子類,所以該異常不一定要捕獲(儘管你可以捕獲只要你願意).作爲 RuntimeException,此類異常不會在 wait (),notify (),notifyAll ()的方法簽名提及。

6.Sleep ()、suspend ()和 wait ()之間有什麼區別? 
       Thread.sleep ()使當前線程在指定的時間處於“非運行”(Not Runnable)狀態。線程一直持有對象的監視器。比如一個線程當前在一個同步塊或同步方法中,其它線程不能進入該塊或方法中。如果另一線程調用了 interrupt ()方法,它將喚醒那個“睡眠的”線程。 
        注意:sleep ()是一個靜態方法。這意味着只對當前線程有效,一個常見的錯誤是調用t.sleep (),(這裏的t是一個不同於當前線程的線程)。即便是執行t.sleep (),也是當前線程進入睡眠,而不是t線程。t.suspend ()是過時的方法,使用 suspend ()導致線程進入停滯狀態,該線程會一直持有對象的監視器,suspend ()容易引起死鎖問題。 
        object.wait ()使當前線程出於“不可運行”狀態,和 sleep ()不同的是 wait 是 object 的方法而不是 thread。調用 object.wait ()時,線程先要獲取這個對象的對象鎖,當前線程必須在鎖對象保持同步,把當前線程添加到等待隊列中,隨後另一線程可以同步同一個對象鎖來調用 object.notify (),這樣將喚醒原來等待中的線程,然後釋放該鎖。基本上 wait ()/notify ()與 sleep ()/interrupt ()類似,只是前者需要獲取對象鎖。 

7.在靜態方法上使用同步時會發生什麼事? 
        同步靜態方法時會獲取該類的“Class”對象,所以當一個線程進入同步的靜態方法中時,線程監視器獲取類本身的對象鎖,其它線程不能進入這個類的任何靜態同步方法。它不像實例方法,因爲多個線程可以同時訪問不同實例同步方法。 







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章