1. 程式人生 > >【面試題】Java面試題--技術深度--個人學習記錄

【面試題】Java面試題--技術深度--個人學習記錄

1、有沒有看過JDK原始碼,看過的類實現原理是什麼。


2、HTTP協議

 

TCP詳解

關於http協議


3、TCP協議

 

TCP詳解

關於http協議


4、一致性Hash演算法


5、JVM如何載入位元組碼檔案

loading、verification、preparation 、 Resolution、initialization 、using 、unloading


6、類載入器如何解除安裝位元組碼(不是很清楚)

堆中的相應物件置為null,清空方法區中對應的二進位制資料結構及其他資料變數等。

關於自定義載入器解除安裝class


7、IO和NIO的區別,NIO優點

網路NIO中的實戰(涉及selector)

NIO很詳細詳解

JavaNIO

同步非同步IO:同步非同步指的是  應用程式與作業系統OS之間的關係,同步需要等待作業系統切換到核心狀態進行IO,等待IO結束後,切換到使用者狀態,繼續執行 ;或者,使用者程式輪詢訪問IO。即同步IO需要參與到IO這個過程。而非同步是交給OS一個IO任務,IO完成後OS會通知應用程式。同異步體現在操作IO的主體,同步的主體是使用者執行緒需要執行最後的IO(包括輪詢),而非同步IO是作業系統執行最後的IO,使用者執行緒只需要獲取資料即可。

阻塞非阻塞IO:

傳統IO即BIO即是阻塞IO,而JDK後面提出的NIO就是非阻塞的IO,阻塞IO需要獲得指定的所有資料才可以返回使用者狀態(或者網路傳輸獲得指定的所有資料)。而非阻塞的IO可以在獲得一部分後即可以返回,在新的資料再次到來時再獲取,並不會阻塞請求執行緒。尤其體現在網路資料接收中,如果使用阻塞IO,針對每一個client,都必須有一個執行緒監聽(IO是斷斷續續的),但是使用非阻塞的時候,只需要很少的執行緒不斷輪詢指定的埠,分別獲取標識的資料即可。不會有很多的執行緒被阻塞住。阻塞非阻塞體現在函式上,會阻塞執行緒。

同步非阻塞:NIO初版。引入buffer,同步即操作主體仍然為使用者執行緒,非阻塞即不會阻塞線上程,但是需要執行緒輪詢檢查IO狀態,buffer的迴圈讀取。

非同步非阻塞:NIO2.0,buffer和回撥,操作主體為核心,OS完成之後即回撥給使用者執行緒並通知。更不會阻塞執行緒。

傳統IO:面向流。即輸入輸出字元位元組流 InputStream、Reader。之後加上了buffer緩衝。總之是字元位元組流的所有擴充套件API。

NIO:面向塊。同步非阻塞IO。引入channel和buffer,檔案輸入流獲取channel→讀入buffer→buffer寫入channel→channel寫入檔案。

NIO優點:1、網路NIO無阻塞(很重要)  2、引入buffer,能夠減少檔案操作次數   3、面向塊,操作速度比傳統IO快。

示例:

public static void copyFileUseNIO(String src,String dst) throws IOException {
        //宣告原始檔和目標檔案
        FileInputStream fi = new FileInputStream(new File(src));
        FileOutputStream fo = new FileOutputStream(new File(dst));
        //獲得傳輸通道channel
        FileChannel inChannel = fi.getChannel();
        FileChannel outChannel = fo.getChannel();
        //獲得容器buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while (true) {
            //判斷是否讀完檔案
            int eof = inChannel.read(buffer);
            if (eof == -1) {
                break;
            }
            //重設一下buffer的position=0,limit=position
            buffer.flip();
            //開始寫
            outChannel.write(buffer);
            //寫完要重置buffer,重設position=0,limit=capacity
            buffer.clear();
        }
        inChannel.close();
        outChannel.close();
        fi.close();
        fo.close();
    }

關於NIO的網路程式設計:此處體現了非阻塞的IO。

流程簡述:有些類似於  severSocket 與 Socket 程式設計。

伺服器端:ServerSocketChannel監聽埠,並多開幾個channel,同時將channel註冊到selector元件裡面,並給selector設定channel發來的感興趣事件(此處是client與server都會設定的東西,4種值),設定好事件後,需要對channel進行迴圈監聽,並且判斷client過來的事件屬性,做出channel資料接收。

客戶端:SocketChannle,初始化hostname與port,將輸入輸入封裝為byte[]  →  byte陣列put進入byteBuffer  →  bufferBuffer寫入channel。


8、Java執行緒池的實現原理,keepAliveTime等引數的作用。

執行緒池,對提交上的執行緒進行統一的管理。使用者建立執行緒但是由執行緒池來管理執行,以及所有執行緒的執行順序、生命週期等,都是由執行緒池管理,使用者不再需要關心執行緒池何時清除。執行緒池

4個建構函式,引數分別是下面引數的部分組合。

執行緒池執行流程是:提交執行緒  →  核心執行緒是否滿?繼續:建立  →  等待對列是否滿?繼續 : 入隊   →   是否超出最大執行緒數?異常處理handler : 繼續   →   非核心是否滿?建立     

  • corePoolSize:核心池的大小,這個引數跟後面講述的執行緒池的實現原理有非常大的關係。在建立了執行緒池後,預設情況下,執行緒池中並沒有任何執行緒,而是等待有任務到來才建立執行緒去執行任務,除非呼叫了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個方法的名字就可以看出,是預建立執行緒的意思,即在沒有任務到來之前就建立corePoolSize個執行緒或者一個執行緒。預設情況下,在建立了執行緒池後,執行緒池中的執行緒數為0,當有任務來之後,就會建立一個執行緒去執行任務,當執行緒池中的執行緒數目達到corePoolSize後,就會把到達的任務放到快取隊列當中;
  • maximumPoolSize:執行緒池最大執行緒數,這個引數也是一個非常重要的引數,它表示線上程池中最多能建立多少個執行緒;
  • keepAliveTime:表示執行緒沒有任務執行時最多保持多久時間會終止。預設情況下,只有當執行緒池中的執行緒數大於corePoolSize時,keepAliveTime才會起作用,直到執行緒池中的執行緒數不大於corePoolSize,即當執行緒池中的執行緒數大於corePoolSize時,如果一個執行緒空閒的時間達到keepAliveTime,則會終止,直到執行緒池中的執行緒數不超過corePoolSize。但是如果呼叫了allowCoreThreadTimeOut(boolean)方法,線上程池中的執行緒數不大於corePoolSize時,keepAliveTime引數也會起作用,直到執行緒池中的執行緒數為0;
  • unit:引數keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態屬性:
TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小時
TimeUnit.MINUTES;           //分鐘
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //納秒
  • workQueue:一個阻塞佇列,用來儲存等待執行的任務,這個引數的選擇也很重要,會對執行緒池的執行過程產生重大影響,一般來說,這裡的阻塞佇列有以下幾種選擇:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;

  ArrayBlockingQueue和PriorityBlockingQueue使用較少,一般使用LinkedBlockingQueue和Synchronous。執行緒池的排隊策略與BlockingQueue有關。

  • threadFactory:執行緒工廠,主要用來建立執行緒;
  • handler:表示當拒絕處理任務時的策略,有以下四種取值:
ThreadPoolExecutor.AbortPolicy:丟棄任務並丟擲RejectedExecutionException異常。 
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不丟擲異常。 
ThreadPoolExecutor.DiscardOldestPolicy:丟棄佇列最前面的任務,然後重新嘗試執行任務(重複此過程)
ThreadPoolExecutor.CallerRunsPolicy:由呼叫執行緒處理該任務 

   具體引數的配置與執行緒池的關係將在下一節講述。

 

而官方不推薦這種方法,而是給出了Executors中的4個靜態建立執行緒池方法,已經定義好部分引數。

CachedThreadPool:可快取的執行緒池,該執行緒池中沒有核心執行緒,非核心執行緒的數量為Integer.max_value,就是無限大,當有需要時建立執行緒來執行任務,沒有需要時回收執行緒,適用於耗時少,任務量大的情況。同步排隊策略

SecudleThreadPool:週期性執行任務的執行緒池,按照某種特定的計劃執行執行緒中的任務,有核心執行緒,但也有非核心執行緒,非核心執行緒的大小也為無限大。適用於執行週期性的任務。特定的一種延遲排隊策略

SingleThreadPool:只有一條執行緒來執行任務,適用於有順序的任務的應用場景。linked排隊策略

FixedThreadPool:定長的執行緒池,有核心執行緒,核心執行緒的即為最大的執行緒數量,沒有非核心執行緒。linked排隊策略

 

針對排隊策略的深層探討:

ArrayBlockingQueue:陣列形式的,有界排隊策略,可以避記憶體被耗光。AQS 抽象排隊同步器
LinkedBlockingQueue:連結串列形式的排隊策略,無界。AQS
SynchronousQueue:同步的,佇列中只能存一個,且這個必須被取走後下一個才能進入。 CAS 比較並交換

AQS 與  CAS(????????AQS CAS  AQS

AQS 即抽象排隊同步器,可重入 reenstrantLock 也是根據內部實現一個自定義同步器來實現的,同步器又分為了  獨佔鎖 和  共享模式,自定義同步器只需要重寫部分方法即可。 並且其中還有 公平 與 非公平的策略提高併發量。

CAS 即比較並交換,現有的值 A 與期待值 B 不一樣,則將現有值 A 賦值為 C,否則不操作,不斷的迴圈請求,並且現有值 A 是通過 volatile 關鍵字修飾的,可以保證每次get的 A 是最新的值,這樣就可以確保執行的執行緒是一個有序的執行緒序列,實現了不加鎖的同步方式。因為CAS是基於樂觀鎖的,也就是說當寫入的時候,如果暫存器舊值已經不等於現值,說明有其他CPU在修改,那就繼續嘗試。所以這就保證了操作的原子性。其中有ABA的缺點,即經過幾次修改變回之前的值A,而被阻塞的執行緒只會判斷值,所以引入版本判別,記錄更改記錄。使用volatile(省掉鎖,卻不能原子性,因為一次賦值操作分為了三步,copy到本地→賦值→重新整理到快取),而Atomic(volatile+CAS),同時起作用實現鎖。關於 volatile 非原子性

參考:

https://www.cnblogs.com/xzn-smy/p/9172555.html

https://blog.csdn.net/wbb_1216/article/details/62882921

http://www.cnblogs.com/Mainz/p/3556430.html

https://blog.csdn.net/aesop_wubo/article/details/7537960

http://m.blog.sina.com.cn/s/blog_ee34aa660102wsuv.html#page=7


9、HTTP連線池實現原理

主要是用來降低 連線次數,因為每次請求都經過三次握手、四次釋放,網路延遲很大。(具體使用方法及原理?????等計算機網路學完部分


10、資料庫連線池實現原理

建立一個管理機制,對connection、statement、result三種資源進行統一的管理,即開有限次資源的介面,交給一個數據結構進行統一的管理,然後釋放執行緒對這個介面的使用權,通過併發控制來決定執行緒擁有公有訪問介面的權利及順序。很類似與執行緒池。https://www.cnblogs.com/newpanderking/p/3875749.html


11、資料庫的實現原理

參考:

http://blog.jobbole.com/100349/

 

資料庫實現原理: