1. 程式人生 > >Java面試題(61-70)

Java面試題(61-70)

61、執行緒池的常用引數有哪些?

在Java中,我們一般通過繼承Thread類和實現Runnnable介面,呼叫執行緒的start()方法實現執行緒的啟動。但如果併發的數量很多,而且每個執行緒都是執行很短的時間便結束了,那樣頻繁的建立執行緒和銷燬執行緒會大大的降低系統執行的效率。執行緒池正是為了解決多執行緒效率低的問題而產生的,他使得執行緒可以被複用,就是執行緒執行結束後不被銷燬,而是可以繼續執行其他任務。

java.uitl.concurrent.ThreadPoolExecutor類是執行緒池中核心的一個類,在ThreadPoolExecutor中提供了四個構造方法。通過原始碼可以發現,前面三個的構造器最後都是呼叫了第四個構造器進行初始化。

public class ThreadPoolExecutor extends AbstractExecutorService {
// .....
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue);

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);

public
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler); //... ...
}

執行緒池引數

  • corePollSize:核心執行緒數。在建立了執行緒池後,執行緒中沒有任何執行緒,等到有任務到來時才建立執行緒去執行任務。預設情況下,在建立了執行緒池後,執行緒池中的執行緒數為0,當有任務來之後,就會建立一個執行緒去執行任務,當執行緒池中的執行緒數目達到corePoolSize後,就會把到達的任務放到阻塞隊列當中。

  • maximumPoolSize:最大執行緒數。表明執行緒中最多能夠建立的執行緒數量。執行緒池中的當前執行緒數目不會超過該值。如果阻塞佇列中任務已滿,並且當前執行緒個數小於maximumPoolSize,那麼會建立新的執行緒來執行任務。

  • allowCoreThreadTimeOut:該屬性用來控制是否允許核心執行緒超時退出。If false,core threads stay alive even when idle.If true, core threads use keepAliveTime to time out waiting for work。如果執行緒池的大小已經達到了corePoolSize,不管有沒有任務需要執行,執行緒池都會保證這些核心執行緒處於存活狀態。可以知道:該屬性只是用來控制核心執行緒的。

  • keepAliveTime:空閒的執行緒保留的時間,如果一個執行緒處在空閒狀態的時間超過了該屬性值,就會因為超時而退出。舉個例子,如果執行緒池的核心大小corePoolSize=5,而當前大小poolSize =8,那麼超出核心大小的執行緒,會按照keepAliveTime的值判斷是否會超時退出。如果執行緒池的核心大小corePoolSize=5,而當前大小poolSize =5,那麼執行緒池中所有執行緒都是核心執行緒,這個時候執行緒是否會退出,取決於allowCoreThreadTimeOut。

  • TimeUnit:空閒執行緒的保留時間單位。

  • BlockingQueue<Runnable>:阻塞佇列,儲存等待執行的任務。引數有ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue可選。

  • ThreadFactory:執行緒工廠,用來建立執行緒

  • RejectedExecutionHandler:佇列已滿,而且任務量大於最大執行緒的異常處理策略。

TimeUnit有以下取值

TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小時
TimeUnit.MINUTES;           //分鐘
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //納秒

RejectedExecutionHandler有以下取值

  • ThreadPoolExecutor.AbortPolicy:丟棄任務並丟擲RejectedExecutionException異常。

  • ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不丟擲異常。

  • ThreadPoolExecutor.DiscardOldestPolicy:丟棄佇列最前面的任務,然後重新嘗試執行任務(重複此過程)

ThreadPoolExecutor.CallerRunsPolicy:由呼叫執行緒處理該任務

62、位元組流與字元流的區別

要把一片二進位制資料資料逐一輸出到某個裝置中,或者從某個裝置中逐一讀取一片二進位制資料,不管輸入輸出裝置是什麼,我們要用統一的方式來完成這些操作,用一種抽象的方式進行描述,這個抽象描述方式起名為 IO 流,對應的抽象類為 OutputStream 和 InputStream ,不同的實現類就代表不同的輸入和輸出裝置,它們都是針對位元組進行操作的。

在應用中,經常要完全是字元的一段文字輸出去或讀進來,用位元組流可以嗎?計算機中的一切最終都是二進位制的位元組形式存在。對於“中國”這些字元,首先要得到其對應的位元組,然後將位元組寫入到輸出流。讀取時,首先讀到的是位元組,可是我們要把它顯示為字元,我們需要將位元組轉換成字元。由於這樣的需求很廣泛,人家專門提供了字元流的包裝類。

底層裝置永遠只接受位元組資料,有時候要寫字串到底層裝置,需要將字串轉成位元組再進行寫入。字元流是位元組流的包裝,字元流則是直接接受字串,它內部將串轉成位元組,再寫入底層裝置,這為我們向 IO 設別寫入或讀取字串提供了一點點方便。

字元向位元組轉換時,要注意編碼的問題,因為字串轉成位元組陣列,其實是轉成該字元的某種編碼的位元組形式,讀取也是反之的道理。

63、什麼是 java 序列化,如何實現 java 序列化?或者請解解釋Serializable 介面的作用。

64、java 中會存在記憶體洩漏嗎,請簡單描述。

java 中的記憶體洩露的情況:長生命週期的物件持有短生命週期物件的引用就很可能發生記憶體洩露,儘管短生命週期物件已經不再需要,但是因為長生命週期物件持有它的引用而導致不能被回收,這就是 java 中記憶體洩露的發生場景,通俗地說,就是程式設計師可能建立了一個物件,以後一直不再使用這個物件,這個物件卻一直被引用,即這個物件無用但是卻無法被垃圾回收器回收的,這就是 java 中可能出現記憶體洩露的情況,例如,快取系統,我們載入了一個物件放在快取中(例如放在一個全域性 map 物件中),然後一直不再使用它,這個物件一直被快取引用,但卻不再被使用。

檢查 java 中的記憶體洩露,一定要讓程式將各種分支情況都完整執行到程式結束,然後看某個物件是否被使用過,如果沒有,則才能判定這個物件屬於記憶體洩露。

如果一個外部類的例項物件的方法返回了一個內部類的例項物件,這個內部類物件被長期引用了,即使那個外部類例項物件不再被使用,但由於內部類持有外部類的例項物件,這個外部類物件將不會被垃圾回收,這也會造成記憶體洩露。

記憶體洩露的另外一種情況:當一個物件被儲存進 HashSet 集合中以後,就不能修改這個物件中的那些參與計算雜湊值的欄位了,否則,物件修改後的雜湊值與最初儲存進 HashSet 集合中時的雜湊值就不同了,在這種情況下,即使在 contains 方法使用該物件的當前引用作為的引數去 HashSet 集合中檢索物件,也將返回找不到物件的結果,這也會導致無法從 HashSet 集合中單獨刪除當前物件,造成記憶體洩露。

65、Spring中Bean的注入方式

Spring依賴注入的三種方式是構造注入、Set注入、註解(@Bean)注入

對於構造注入,Spring在建立Bean例項時,需要同時例項化其依賴的全部例項。

對於複雜的依賴關係,若使用構造注入,會導致構造器過於臃腫。

在bean元素中使用constructor-arg元素來設值屬性值的建構函式注入,可以通過該元素的type屬性指定引數型別,index屬性指定該引數在建構函式引數列表中的索引位置。

66、簡述ApplicationContext介面

ApplicationContext是BeanFactory的子介面,ApplicationContext接口裡麵包含了BeanFactory的所有功能,並提供了一些擴充套件,比如更容易同SpringAOP特性整合,資原始檔的處理,Spring為ApplicationContext提供的3種實現分別為:ClassPathXmlApplicationContext,FileSystemXmlApplicationContext和XmlWebApplicationContext。

67、Spring程式設計式事務管理和宣告式事務管理的區別

Spring提供的事務管理可以分為兩類:程式設計式和宣告式。

  • 程式設計式通過程式碼實現,比較直接,但是程式碼量大,重複的程式碼比較多,不易維護;Spring提供兩種方式的程式設計式事務管理,分別是使用TransactionTemplate和直接使用PlatformTransactionManager。

  • 宣告式比程式設計式更靈活。宣告式事務管理通過AOP實現,這是最少影響應用程式碼的選擇。

68、Spring MVC的處理流程

69、Spring中@Transactional事務回滾

70、Java中的強引用、軟引用、弱引用、虛引用