1. cpu通過時間片分配算法來循環執行任務,當前任務執行一個時間片后會切換到下一任務。但是,再切換之前會保存上一任務的狀態,以便下次切換回這個任務時,可以再加載這個任務的狀態。所以任務從保存到再加載的過程就是一次上下文切換。
2. 多線程一定快嗎?
不一定。并發執行累加操作不超過百萬次時,速度比串行執行累加操作要慢。因為線程有創建和上下文切換的開銷。
3. 如何減少上下文的切換?
無鎖并發編程,CAS算法,使用最少線程和使用協程
無鎖并發編程:多線程競爭鎖時,會引起上下文切換,所以多線程處理數據時,可以用一些方法來避免鎖,如將數據的id按照hash算法取模分段,不同的線程處理不同段的數據
CAS算法:Java的Atomic包使用CAS算法來更新數據,不需要加鎖
使用最少線程:避免創建不需要的線程,比如任務很少,但是創建了很多線程來處理,這樣會造成大量線程都處于等待狀態
協程:在單線程里實現多任務的調度,并在單線程里維持多個任務間的切換
4. 避免死鎖的常見方法:
避免一個線程同時獲取多個鎖
避免一個線程在鎖內同時占用多個資源,保證每個鎖只占用一個資源
嘗試使用定時鎖,使用lock.tryLock(timeout)來替代使用內部鎖機制
對于數據庫鎖,加鎖和解鎖必須在一個數據庫連接里,否則會出現解鎖失敗的情況
5. Volatile的定義與實現原理:
定義:Java編程語言允許線程訪問共享變量,為了確保共享變量能被準確和一致地更新,線程應該確保通過排他鎖單獨獲得這個變量。如果一個字段被聲明成volatile,Java線程內存模型確保所有線程看到這個變量地值是一致的。
實現原則:Lock前綴指令會引起處理器緩存回寫到內存,一個處理器的緩存回寫到內存會導致其他處理器的緩存無效
6. synchronized的實現原理與應用:
實現同步的基礎:Java中的每一個對像都可以作為鎖。具體表現為:
對于普通同步方法,鎖時當前實例對象
對于靜態同步方法,鎖是當前類的class對象
對于同步方法塊,鎖是synchronized括號里配置的對象
當一個線程試圖訪問同步代碼塊時,它首先必須得到鎖,退出或拋出異常時必須釋放鎖。
實現原理:jvm基于進入和退出Monitor對象來實現方法同步和代碼塊同步,但兩者的實現細節不一樣。代碼塊同步時使用monitorenter和monitorexit指令實現的,而方法同步是使用另外一種方式實現的,但是方法的同步同樣可以使用這兩個指令來實現。Monitorenter指令是在編譯后插入到同步代碼塊的開始位置,而monitorexit是插入到方法結束處和異常處,JVM要保證每個monitorenter必須有對應的monitorexit與之配對。任何對象都有一個monitor與之相連,當且一個monitor被持有后,它將處于鎖定狀態。線程執行到monitorenter指令時,將會嘗試獲取對象所對應的monitor的所有權,即嘗試得對象的鎖。
7. Java對象頭
Synchronized用的鎖是存在Java對象頭里的。如果對象是數組類型,虛擬機用3個字寬存儲對象頭,否則用2字寬存儲對象頭。
8. 鎖的狀態:
無鎖狀態,偏向鎖狀態,輕量級鎖狀態,重量級鎖狀態
鎖可以升級但不能降級,這種策略是為了提高獲得鎖和釋放鎖的效率
9. 偏向鎖:
定義:它會偏向于第一個訪問鎖的線程,如果在運行過程中,同步鎖只有一個線程訪問,不存在多線程爭用的情況,則線程是不需要觸發同步的,這種情況下,就會給線程加一個偏向鎖。如果在運行過程中,遇到了其他線程搶占鎖,則持有偏向鎖的線程會被掛起,JVM會消除它身上的偏向鎖,將鎖恢復到標準的輕量級鎖。
偏向鎖的實現:
獲取過程:
- 訪問Mark Word中偏向鎖的標識是否設置成1,鎖標志位是否為01,確認為可偏向狀態
- 如果為可偏向狀態,則測試線程id是否指向當前線程。如果是,進入步驟5,否則進入步驟3
- 如果線程id并未指向當前線程,則通過CAS操作競爭鎖。如果競爭成功,則將Mark Word中線程id設置為當前線程id,然后執行步驟5,如果競爭失敗,執行步驟4
- 如果CAS獲取偏向鎖失敗,則表示有競爭。當到達全局安全點時獲得偏向鎖的線程被掛起,偏向鎖升級為輕量級鎖,然后被阻塞在安全點的線程繼續往下執行同步代碼
- 執行同步代碼
釋放過程:
偏向鎖使用了一種等待競爭出現才釋放鎖的機制,所以當其他線程嘗試競爭偏向鎖時,持有偏向鎖的線程才會釋放鎖。偏向鎖的撤銷,需要等待全局安全點(在這個時間點上沒有正在執行的字節碼),它會首先咱潛艇擁有偏向鎖的進程,判斷鎖對象是否處于被鎖定狀態,撤銷偏向鎖后恢復到未鎖定(標志位01)或輕量級鎖(標志位00)的狀態
10. 輕量級鎖
輕量級鎖時由偏向鎖升級而來的,偏向鎖運行在一個線程進入同步塊的情況下,當dierge 線程加入鎖爭用的時候,偏向鎖就會升級成輕量級鎖
加鎖:
- 代碼進入同步快的時候,如果同步對象鎖狀態為無鎖狀態,虛擬機首先將在當前線程的棧幀中建立一個名為鎖記錄(Lock Reocrd)的空間,用于存儲對象目前的Mark Word的拷貝。
- 拷貝對象頭中的Mark Word復制到鎖記錄中
- 拷貝成功后,虛擬機將使用CAS操作嘗試將對象的Mark Word更新為指定的Lock Reocrd的指針,官方稱為Displaced Mark Word并將Lock Reocrd里的owner指針指向object mark word。如果成功,執行步驟4,否則執行步驟5
- 線程擁有該對象的鎖,并且對象Mark Word的鎖標志位設置為00,表示此對象處于輕量級鎖定狀態
- 如果失敗,虛擬機首先會檢查對象的Mark Word是否指向當前線程的棧幀,如果時是則說明當前線程已經擁有了這個對象的鎖,那就可以直接進入同步塊繼續執行。斗則說明多個線程競爭鎖,輕量級鎖就要膨脹為重量級鎖,鎖標志的狀態值變為10,Mark Word中存儲的就是指向重量級鎖的指針,后面等待鎖的線程也要進入阻塞狀態。而當前線程便嘗試使用自旋來獲取鎖,自旋就是為了不讓線程阻塞,而采取循環取獲取鎖的過程。
解鎖:
會使用原子的CAS操作將Displaced Mark Word替換回到對象頭,如果成功則表示沒有競爭發生,如果失敗,表示當前鎖存在競爭,鎖就會膨脹成重量級鎖。
11. 鎖的優缺點對比:
12. 線程
定義:現在操作系統在運行一個程序時,會為其創建一個進程。現代操作系統調度的最小單元是線程,也叫輕量級進程,在一個進程里可以創建多個線程,這些線程都擁有各自的計數器,堆棧和局部變量等屬性,并且能夠訪問共享的內存變量。
程序在各自的進程中進行:相互分離,各自獨立執行,由操作系統來分配資源,比如內存,文件句柄,安全證書。進程h會通過一些原始的機制相互通信:socket,信號處理,共享內存,信號量。
線程優先級:在Java線程中,通過一個整型成員變量priority來控制優先級,優先級的范圍從1—10,線程構建的時候可以通過setPriority(int)方法來修改優先級,優先級高的線程分配時間片的數量要多余優先級第的線程。
線程的狀態:
New 初始狀態,線程被構建,但是還沒有調用start()方法
Runnable 運行狀態,java線程將操作系統中的就緒和運行兩種狀態籠統地稱作“運行中”
Blocked 阻塞狀態,表示線程阻塞于鎖
Waiting 等待狀態,表示線程進入等待狀態,進入該狀態表示當前線程需要等待其他線程做出一些特定動作(通知或中斷)
Time_waiting 超時等待狀態,該狀態不等同于waiting,她是可以在指定地時間自行返回的
Terminated 終止狀態,表示當前線程已經執行完畢
線程的狀態變遷:
線程創建之后調用start()方法開始運行。當線程執行wait()方法之后,線程進入等待狀態。進入等待狀態的線程需要依靠其他線程的通知才能返回運行狀態,而超時等待狀態相當于在等待狀態的基礎上增加了超時限制,也就是超時時間到達時將會返回運行狀態。當線程調用永不方法時,在沒有獲取到鎖的情況下,線程將會進入到阻塞狀態。線程在執行Runnable的run()方法之后將會進入到終止狀態。
(阻塞狀態是線程阻塞在進入synchronized關鍵字修飾的方法或代碼塊時的狀態,但是阻塞在java.concurrent包中Lock接口的線程狀態確是等待狀態,因為java.concurrent包中Lock接口對于阻塞的實現均使用了LockSupport類中的相關方法)
13. Daemon線程
Daemon線程是一種支持型線程,因為它主要被用作程序中后臺調度以及支持性工作。這意味著,當一個Java虛擬機中不存在非Daemon線程的時候,Java虛擬機將會退出。可以通過調用Thread.setDaemon(true)將賢臣設置為Daemon線程
(Daemon屬性需要在啟動線程之前設置,不能在啟動線程之后設置。Daemon線程被用作完成支持性工作,但是在Java虛擬機退出時Daemon線程中的finally塊并不一定會執行,所以構建Daemon線程時,不能依靠finally塊中的內容來確保執行關閉或清理資源的邏輯)
14. 不建議使用suspend(),resume(),stop()方法完成線程暫停,恢復和終止工作的原因:
Suspend()方法:在調用后,縣城不會釋放已經占有的資源(比如鎖),而是占著資源進入睡眠狀態,這樣容易引發死鎖問題。同樣stop()方法在終結一個線程時不會保證線程的資源正常釋放,通常是沒有給與線程完成資源釋放工作的機會,因此會導致程序可能工作在不確定狀態下
15. 安全終止線程
中斷操作時一種簡便的線程間交互方式,而這種交互方法最適合用來取消或停止任務,除了中斷以外,還可以利用一個boolean變量來控制是否需要停止任務來終止該線程。
16. 中斷
中斷可以理解為線程的一個標識位屬性,它表示一個運行中的線程是否被其他線程進行了中斷操作。中斷好比其他的線程對該線程打了個招呼,其他線程通過調用該線程的interrupt()方法對其進行中斷操作。
17. Volatile和synchronized關鍵字
Java支持多個線程同時訪問一個對象或者對象的成員變量。由于每個線程可以擁有這個變量的拷貝,所以程序在執行過程中,一個線程看到的變量并一定是最新的。
關鍵字volatile可以用來修飾字段(成員變量),告知程序任何對該變量的訪問均需要從共享內存中獲取,而對它的改變必須同步刷新共享內存,它能保證所有線程對變量訪問的可見性。
關鍵字synchronized可以修飾方法或者以同步塊的形式來進行使用,它主要確保多個線程在同一時刻,只能有一個線程處于方法或者同步塊中,它保證了線程對變量訪問的可見性和排他性。
18. 等待/通知的相關方法
等待/通知機制,是指一個線程A調用了對象O的wait()方法進入等待狀態,而另一個線程B調用了對象O的notify()或者notifyAll()方法,線程A收到通知后從對象O的wait()方法返回,進而執行后續操作。上述兩個線程通過對象O來完成交互,而對象上的wait
()和notify/notifyAll()的關系就如同開關信號一樣,用來完成等待方和通知方之間的交互工作。
注意點:
- 使用wait(),notify(),notifyAll()時需要先對調用對象加鎖
- 調用wait()方法后,線程狀態由running變成waiting,并將當前線程放置到對象的等待序列
- Notify()或notifyAll()方法調用后,等待線程依舊不會從wait()返回,需要調用notify()或notifyAll()的線程釋放鎖之后,等待線程才有機會從wait()返回
- Notify()方法將等待隊列中的一個等待線程從等待隊列中移到同步隊列中,而notifyAll()方法則是將等待隊列中所有的線程全部移到同步隊列,被移動的線程狀態由waiting變為blocked
- 從wait()方法返回的前提是獲得了調用對象的鎖
19. 管道輸入/輸出流
用于線程之間的數據傳輸,而傳輸的媒介為內存
具體實現:PipedOutStream,PipedInputStream,PipedReader,PipedWriter,前兩種面向字節,后兩種面向字符。
注意:對于piped類型的流,必須先要進行綁定,也就是調用connect()方法,如果沒有將輸入/輸出流綁定起來(out.connect(in)),對于該流的訪問將會拋出異常(IOException)。
20. Thread.join()的使用
如果一個線程A執行了Thread.join()語句,含義是:當前線程A等待thread線程終止之后,才從thread.join()返回。
21. ThreadLocal
線程變量,是一個以ThreadLocal對象為鍵,任意對象為值的存儲結構。這個結構被附帶在線程上,也就是說一個線程可以根據一個ThreadLocal對象查詢到綁定在這個線程上的一個值。
可以通過set(T)方法來設置值,在房前線程下再通過get()方法獲取到原先設置的值
22. 等待/通知經典范式:
加鎖,條件循環,處理邏輯
23. 超時等待模式:
在等待/通知范式基礎上增加了超時控制,即使方法執行時間長,也不會永久阻塞調用者,而是會按照調用者的要求按時返回
24. Lock接口
鎖是用來控制多個線程訪問共享資源的方式,一般來說,一個鎖能夠防止多個線程同時訪問共享資源(但是有些鎖可以允許多個線程并發的訪問共享資源,比如讀寫鎖)。Lock接口提供了與synchronized關鍵字類似的同步功能,只是在使用時需要顯示的獲取和釋放鎖。雖然它缺少了隱式獲取釋放鎖的便捷性,但是卻擁有了鎖獲取與釋放的可操作性,可中斷的獲取鎖以及超時獲取鎖等多種synchronized關鍵字所不具備的同步特性
25. ConsurrentHashMap:線程安全又高效的hashMap
線程允許程序控制流的多重分支同時存在于一個進程。它們共享進程范圍內的資源,比如內存和文件句柄,但是每一個線程有其自己的程序計數器,棧和本地變量。
恰當的使用線程,可以降低開發和維護的開銷,能夠提高復雜應用的性能。
當多個線程訪問一個類時,如果不用考慮這些線程在運行時環境下的調度和交替執行,并且不需要額外的同步及在調用方代碼不必作其他的協調,這個類的行為仍然是正確的,那么稱這個類是線程安全的。
26. Java中合理使用線程池的好處
第一:降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的消耗
第二:提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行
第三:提高線程的可管理性。線程是稀缺資源,如果無限制地創建,不僅會消耗系統資源,還會降低系統地穩定性,使用線程池可以進行統一分配,調優和監控。
27. 線程池的實現原理
當提交一個新任務到線程池時,線程池的處理流程:
1) 線程池判斷核心線程池里的線程是否都在執行任務。如果不是,則創建一個新的工作線程來執行任務。如果核心線程池里的線程都在執行任務,則進入下個流程
2) 線程池判斷工作隊列是否已經滿。如果工作隊列沒有滿,則將新提交的任務存儲在這個工作隊列里。如果工作隊列滿了,則進入下個流程。
3) 線程池判斷線程池的線程是否都處于工作狀態。如果沒有,則創建一個新的工作線程來執行任務。如果已經滿了,則交給飽和策略來處理這個任務。
ThreadPoolExecutor執行execute方法分下面4種情況:
1) 如果當前運行的線程少于corePoolSize,則創建新線程來執行任務。
2) 如果運行的線程等于或多余corePoolSize,則將任務加入BlockingQuene。
3) 如果無法將任務加入BlockingQuene(隊列已滿),則將創建新的線程來處理任務。
4) 如果創建新線程將使當前運行的線程超出maximumPoolSize,任務將被拒絕,并調用RejectedExecutionHandler.rejectedExecution()方法
5)
競爭條件:當計算的正確性依賴于運行中相關的時序或者多線程的交替時,會產生競爭條件。最常見的一種競爭條件是:檢查再運行,使用一個潛在的過期值作為決定下一步操作的依據。
線程:
線程指在程序執行過程中,能夠執行程序代碼的一個執行單位。每個程序至少都有一個線程,也就是程序本身。
線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。程序員可以通過它進行多處理器編程,你可以使用多線程對運算密集型任務提速。
線程和進程:
線程是進程的子集,一個進程可以有很多線程,每條線程并行執行不同的任務。不同的進程使用不同的內存空間,而所有的線程共享一片相同的內存空間。每個線程又擁有單獨的棧內存用來存儲本地數據
在Java中實現線程:
Java.lang.Thread類的實例就是一個線程,但是需要調用java.lang.Runnable接口來執行,由于線程類本身就是調用的Runnable接口,所以你可以繼承java.lang.Thread類或者直接調用Runnable接口來重寫run()方法來實現線程
用Runnable還是Thread:
Java不支持類的多重繼承,但允許調用多個接口,如果你需要繼承其他類,當然是調用Runnable接口
Thread類中的start()和run()的區別:
Start()方法被用來啟動新創建的線程,而且start()內部調用了run()方法,這和直接調用run()方法的效果不一樣。當調用run()方法時,只會是在原來的線程中調用,沒有新的線程啟動,start()方法才會啟動新線程
Java中的Runnable和Callable的不用:
Runnable和Callable都代表那些要在不同的線程中執行的任務。它們的主要區別時Callable的call()方法可以返回值和拋出異常,而Runnable的run()方法沒有這些功能
Java中CyclicBarrier和CountDownLatch的不同:
CyclicBarrier和CountDownLatch都可以用來讓一組線程等待其他線程。與CyclicBarric不同的是,countdownLatch不能重新使用
Java中的volatile變量:
Volatile是一個特殊的修飾符,只有成員變量才能使用它,在Java并發程序缺少同步類的情況下,多線程對成員變量的操作就是對其他線程是透明的。Volatile變量可以保證下一個讀取操作會在前一個寫操作之后發生
線程安全:
如果代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。一個線程安全的計數器類的同一個實例對象在被多個線程使用的情況下也不會出現計算失誤。很顯然集合類有兩組:線程安全和非線程安全。Vector是用同步方法來實現線程安全的,而arraylist不是線程安全的
Java中的競態條件
競態條件會導致程序在并發情況下出現一些bugs。多線程對一些資源的競爭的時候就會產生競態條件,如果首先要執行的程序競爭失敗排到后面執行了,那么整個程序就會出現一些不確定的bugs。這中bugs很難發現而且會重復出現,因為線程間的隨機競爭。
Java中停止一個線程:
當run()或者call()方法執行完的時候線程會自動結束,如果要手動結束一個線程,可以用volatile布爾變量來退出run()方法的循環或者是取消任務來中斷線程
一個線程運行時發生異常會怎樣:
如果異常沒有被捕獲該線程將會停止執行。Thread.UncaughtExceptionHandler是用來處理未捕獲異常造成線程突然中斷情況的一個內嵌接口。當一個為捕獲異常將造成線程中斷的時候jvm會使用Thread.UncaughtExceptionHandler()來查詢線程的UncaughtExceptionHandler并將線程和異常作為參數傳遞給handler的uncaughtException()方法進行處理。
如何在兩個線程間共享數據:
通過共享對象來實現,或者是使用像阻塞隊列這樣并發的數據結構
Java中notify和notifyAll的區別:
Notify()方法不能喚醒某個具體的線程,所以只有一個線程在等待的時候它才有用武之地。而notifyAll()喚醒所有線程并允許它們爭奪鎖確保了至少有一個線程能繼續運行
Wait,notify和notifyAll方法不在thread類里面:
Java提供的鎖是對象級而不是線程級的,每個對象都有鎖,通過線程獲得。如果線程需要等待某些鎖那么調用對象中的wait()方法就有意義了。如果wait()方法定義在thread類中,線程等待的是哪個鎖就不明顯了。簡單的來說,由于wait,notify和notifyAll都是鎖級別的操作,所及把它們定義在object類中因為鎖屬于對象
ThreadLocal變量:
ThreadLocal是Java里一種特殊的變量。每個線程都有一個Threadlocal就是每個線程都有自己獨立的一個變量,競爭條件被徹底消除了。它是創建代價高昂的對象獲取線程安全的好辦法。可以用ThreadLocal讓SimpleDateFormat變成線程安全的。
Wait和notify方法要在同步塊中調用:
Java api強制要求這樣做,如果不這么做,代碼會拋出IlegalMonitorStateException異常;為了避免wait和notify之間產生競態條件
Java多線程中的死鎖:
死鎖是兩個或兩個以上的進程在執行過程中,因爭奪資源造成的一種相互等待的現象,若無外力作用,它們將無法推進下去,死鎖會讓你的程序掛起無法執行任務。
死鎖滿足以下條件:
互斥條件:一個資源每次只能被一個進程使用
請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放
不剝奪條件:進程獲得的資源,在未使用完之前,不能強行剝奪
循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系
避免死鎖的最簡單的方法就是組織循環等待條件,將系統中所有的資源設置標志位,排序,規定所有的進程申請資源必須以一定的順序做操作來避免死鎖
Java中活鎖和死鎖的區別:
活鎖和死鎖類似,不同之處在于處于活鎖的進程或線程的狀態是不斷改變的,活鎖可以認為時一種特殊的饑餓。簡單來說就是,活鎖和死鎖的主要區別是前者進程的狀態可以改變但是卻不能繼續執行
檢測一個線程是否擁有鎖:
Java.lang.Thread中的holdLock(),它返回true,表示當前線程擁有某個具體對象的鎖
Jvm中哪個參數是用來控制線程的棧堆大小的:
-Xss參數用來控制線程的堆棧大小
Thread類中的yield方法:
Yield方法可以暫停當前正在執行的線程對象,讓其他有享用優先級的線程執行。它是一個靜態方法而且只保證當前線程放棄cpu占用而不能保證使其它線程一定能占用cpu,執行yield()的線程有可能在進入到暫停狀態后馬上又被執行
T1,T2,T3三個線程如何確保它們按順序執行:
可以使用線程類的join()方法在一個線程中啟動另一個線程,另外一個線程完成該線程繼續執行。為了確保三個線程的順序,應該先啟動最后一個(T3調用T2,T2調用T1),這樣T1就會先完成而T3最后完成。
如何強制啟動一個線程?
無法強制啟動,它是被線程調度器控制的
Java多線程中調用wait()和sleep()方法有什么不同?
Wait方法用于線程間通信,如果等待條件為真或其他線程被喚醒時它會釋放鎖,而sleep方法僅僅釋放cpu資源或者讓當前線程停止一段時間,但不會釋放鎖。
Sleep和wait的區別:
Sleep時使線程停止一段時間的方法,在sleep時間間隔期滿后,線程不一定立即恢復執行。因為在那個時刻,其他線程可能正在運行,而且沒有被調度為放棄執行,除非醒來的線程具有更高的優先級,或者正在運行的線程因為其他原因被阻塞
Wait:當線程交互時,如果線程堆一個對象x發出一個wait調用,該線程會暫停執行,被調對象進入等待狀態,直到被喚醒或等待時間到。
同步和異步:
如果數據將在線程間共享,例如正在些的數據以后可能被另一個線程讀到,或者正在讀的數據可能已經被另一個線程寫過了,那么這次額數據就是共享數據,必須進行同步存取。當應用程序在對象上調用了一個需要花費很長時間來執行的方法,并且不希望讓程序等待方法的返回,就應該使用異步編程。在很多情況下采取異步更有效率
Synchronized和Java.util.concurrent.locks.Lock的異同:
相同點:Lock能完成synchronized所實現的所有功能。
不同點:Lock有比Synchronized更景區的線程語義和更好的性能。Synchronized會自動釋放鎖,lock要求手工釋放,并且必須在finally從句中釋放。
串行化:
概念:對象壽命隨著生成該對象的程序終止而終止。有時候,可能需要將對象的狀態保存下來,在需要時再將對象恢復。對象的這種能記錄自己的狀態一遍將來再生的能力叫做對象的持續化。對象通過描述自己狀態的數值來記錄自己,這個過程叫做對象串行化/串行化的主要任務是寫出對象實例變量的數值。如果變量使另一對象的引用,則引用的對象也要串行化。
在Java.io包中,接口serializable用來作為實現對象串行化的工具,只有實現了serializable的類的對象才可以被串行化。
Transient是Java語言的關鍵字,用來表示一個域不是該對象串行化的一部分
如果你提交任務時,線程池隊列已滿,會發生什么?
如果一個任務不能被調度執行,那么submit()方法將會拋出RejectedExecutionException異常
進程和線程的內存結構不同
進程之間是不能共享內存的,而線程可以