一、執行緒sleep和wait有什麼區別
- 這兩個方法來自不同的類分別是Thread和Object
- 最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他執行緒可以使用同步控制塊或者方法。
- wait,notify和notifyAll只能在同步控制方法或者同步控制塊裡面使用,而sleep可以在任何地方使用
synchronized(x){
x.notify()
//或者wait()
}
複製程式碼
- sleep必須捕獲異常,而wait,notify和notifyAll不需要捕獲異常
二、 程式和執行緒的關係
(1)一個執行緒只能屬於一個程式,而一個程式可以有多個執行緒,但至少有一個執行緒。
(2)資源分配給程式,同一程式的所有執行緒共享該程式的所有資源
(3)處理機分給執行緒,即真正在處理機上執行的是執行緒。
(4)執行緒在執行過程中,需要協作同步。不同程式的執行緒間要利用訊息通訊的辦法實現同步。執行緒是指程式內的一個執行單元,也是程式內的可排程實體.
複製程式碼
程式與執行緒的區別:
(1)排程:執行緒作為排程和分配的基本單位,程式作為擁有資源的基本單位
(2)併發性:不僅程式之間可以併發執行,同一個程式的多個執行緒之間也可併發執行
(3)擁有資源:程式是擁有資源的一個獨立單位,執行緒不擁有系統資源,但可以訪問隸屬於程式的資源.
(4)系統開銷:在建立或撤消程式時,由於系統都要為之分配和回收資源,導致系統的開銷明顯大於建立或撤消執行緒時的開銷。
複製程式碼
同步和互斥的區別:
當有多個執行緒的時候,經常需要去同步這些執行緒以訪問同一個資料或資源。例如,假設有一個程式,其中一個執行緒用於把檔案讀到記憶體,而另一個執行緒用於統計檔案中的字元數。當然,在把整個檔案調入記憶體之前,統計它的計數是沒有意義的。但是,由於每個操作都有自己的執行緒,作業系統會把兩個執行緒當作是互不相干的任務分別執行,這樣就可能在沒有把整個檔案裝入記憶體時統計字數。為解決此問題,你必須使兩個執行緒同步工作。
所謂同步,是指散步在不同程式之間的若干程式片斷,它們的執行必須嚴格按照規定的某種先後次序來執行,這種先後次序依賴於要完成的特定的任務。如果用對資源的訪問來定義的話,同步是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源。
所謂互斥,是指散佈在不同程式之間的若干程式片斷,當某個程式執行其中一個程式片段時,其它程式就不能執行它們之中的任一程式片段,只能等到該程式執行完這個程式片段後才可以執行。如果用對資源的訪問來定義的話,互斥某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
三、Serializable 和Parcelable 的區別
-
在使用記憶體的時候,Parcelable比Serializable效能高,所以推薦使用Parcelable。
-
Serializable在序列化的時候會產生大量的臨時變數,從而引起頻繁的GC。
-
Parcelable不能使用在要將資料儲存在磁碟上的情況,因為Parcelable不能很好的保證資料的持續性在外界有變化的情況下。儘管Serializable效率低點,但此時還是建議使用Serializable 。
四、JAVA執行緒間的狀態轉換
1.新建(new):新建立了一個執行緒物件。
2. 可執行(runnable):執行緒物件建立後,其他執行緒(比如main執行緒)呼叫了該物件的start()方法。該狀態的執行緒位於可執行執行緒池中,等待被執行緒排程選中,獲取cpu 的使用權 。
3. 執行(running):可執行狀態(runnable)的執行緒獲得了cpu 時間片(timeslice) ,執行程式程式碼。
4. 阻塞(block):阻塞狀態是指執行緒因為某種原因放棄了cpu 使用權,也即讓出了cpu timeslice,暫時停止執行。直到執行緒進入可執行(runnable)狀態,才有機會再次獲得cpu timeslice 轉到執行(running)狀態。阻塞的情況分三種:
(一). 等待阻塞:執行(running)的執行緒執行o.wait()方法,JVM會把 該執行緒放入等待佇列(waitting queue)中。
(二). 同步阻塞:執行(running)的執行緒在獲取物件的同步鎖時,若該同步鎖被別的執行緒佔用,則JVM會把該執行緒放入鎖池(lock pool)中。
(三). 其他阻塞:執行(running)的執行緒執行Thread.sleep(long ms)或t.join()方法,或者發出了I/O請求時,JVM會把該執行緒置為阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或者超時、或者I/O處理完畢時,執行緒重新轉入可執行(runnable)狀態。
5. 死亡(dead):執行緒run()、main() 方法執行結束,或者因異常退出了run()方法,則該執行緒結束生命週期。死亡的執行緒不可再次復生。
五、常用容器繼承關係圖
容器原始碼理解
-
HashTable
規範1:若重寫equals(Object obj)方法,有必要重寫hashcode()方法,確保通過equals(Object obj)方法判斷結果為true的兩個物件具備相等的hashcode()返回值。說得簡單點就是:“如果兩個物件相同,那麼他們的hashcode應該相等”。不過請注意:這個只是規範,如果你非要寫一個類讓equals(Object obj)返回true而hashcode()返回兩個不相等的值,編譯和執行都是不會報錯的。不過這樣違反了Java規範,程式也就埋下了BUG。 規範2:如果equals(Object obj)返回false,即兩個物件“不相同”,並不要求對這兩個物件呼叫hashcode()方法得到兩個不相同的數。說的簡單點就是:“如果兩個物件不相同,他們的hashcode可能相同”。
根據這兩個規範,可以得到如下推論:
- 1、如果兩個物件equals,Java執行時環境會認為他們的hashcode一定相等。
- 2、如果兩個物件不equals,他們的hashcode有可能相等。
- 3、如果兩個物件hashcode相等,他們不一定equals。
- 4、如果兩個物件hashcode不相等,他們一定不equals。
六、陣列和連結串列的區別
記憶體儲存:
① 陣列從棧中分配空間,對程式設計師方便快速,自由度小。
② 連結串列從堆中分配記憶體。自由度大但申請管理比較麻煩。
邏輯結構:
① 陣列必須事先定義固定的長度(元素個數),不能適應資料動態地增減情況(資料插入、刪除比較麻煩)。當資料增加時,可能會超出陣列的最大空間(越界);當資料減少時,造成記憶體浪費。
② 連結串列動態地進行儲存分配,可以適應資料動態地增減情況(資料插入刪除簡單)(陣列中插入、刪除資料項時,需要移動其他項),但連結串列查詢元素時需要遍歷整個連結串列。
複製程式碼
七、淺拷貝和深拷貝
八、常用網路協議
- TCP/IP在連線時有幾次握手?釋放時有幾次握手?
- 什麼是TCP協議?UDP協議?區別?
- 什麼是cookie?session和cookie有什麼區別?
九、多執行緒
1、開啟執行緒的三種方式
通過Callable和Future建立執行緒(1)建立Callable介面的實現類,並實現call()方法,該call()方法將作為執行緒執行體,並且有返回值。
(2)建立Callable實現類的例項,使用FutureTask類來包裝Callable物件,該FutureTask物件封裝了該Callable物件的call()方法的返回值。
(3)使用FutureTask物件作為Thread物件的target建立並啟動新執行緒。
(4)呼叫FutureTask物件的get()方法來獲得子執行緒執行結束後的返回值
九、執行緒同步小結
- 執行緒同步的目的是為了保護多個執行緒反問一個資源時對資源的破壞。
- 執行緒同步方法是通過鎖來實現,每個物件都有切僅有一個鎖,這個鎖與一個特定的物件關聯,執行緒一旦獲取了物件鎖,其他訪問該物件的執行緒就無法再訪問該物件的其他同步方法。
- 對於靜態同步方法,鎖是針對這個類的,鎖物件是該類的Class物件。靜態和非靜態方法的鎖互不干預。一個執行緒獲得鎖,當在一個同步方法中訪問另外物件上的同步方法時,會獲取這兩個物件鎖。
- 對於同步,要時刻清醒在哪個物件上同步,這是關鍵。
- 編寫執行緒安全的類,需要時刻注意對多個執行緒競爭訪問資源的邏輯和安全做出正確的判斷,對“原子”操作做出分析,並保證原子操作期間別的執行緒無法訪問競爭資源。
- 當多個執行緒等待一個物件鎖時,沒有獲取到鎖的執行緒將發生阻塞。
- 死鎖是執行緒間相互等待鎖鎖造成的,在實際中發生的概率非常的小。真讓你寫個死鎖程式,不一定好使,呵呵。但是,一旦程式發生死鎖,程式將死掉。