1. 程式人生 > >JAVA程式設計試題集合2

JAVA程式設計試題集合2

1舉例說明程式設計中的幾種鎖

1.悲觀鎖和樂觀鎖—悲觀鎖(Pessimistic Lock), 很悲觀,每次拿資料都會上鎖,這樣別人想拿這個資料就會block直到獲取鎖。傳統關係型資料庫用到很多這種鎖,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在操作前先上鎖。樂觀鎖(Optimistic Lock), 很樂觀,每次拿資料時都認為別人不會修改,所以不上鎖,但更新時會判斷在此期間別人有沒有更新這個資料,可使用版本號等機制。 兩種鎖各有優缺點,不可認為一種好於另一種,樂觀鎖適用於讀多寫少的情況,即衝突真的很少發生,這樣可以省去鎖開銷,加大系統吞吐量。但如果經常有衝突(併發量大),上層應用會不斷重試(判斷經常不通過),這樣反倒降低效能,所以用悲觀鎖就比較合適(高併發下修改資料庫的同一行資料)。

2.讀寫鎖:允許多個讀操作同時進行,但每次只允許一個寫操作。讀寫鎖是一種效能優化策略。讀資料時使用讀鎖,寫資料時使用寫鎖,如果沒有寫鎖時,讀是無阻塞的,能提高程式執行效率。

3.自旋鎖:自旋鎖使執行緒在沒有取得鎖時不掛起,而去執行空迴圈(自旋),若干個空迴圈後如果可以獲得鎖則繼續執行。若依然不能獲得鎖才被掛起。使用自旋鎖後執行緒被掛起機率相對減少,執行緒執行連貫性得到加強。對於鎖競爭激烈、鎖佔用時間很短的併發執行緒,具有積極意義,但對於鎖競爭激烈,單執行緒鎖佔用很長時間的併發程式,自旋鎖在自旋等待後還是無法獲得鎖,不僅僅浪費CPU時間,最終還被掛起,反而浪費了系統資源。

2 解釋一下RPC

  • RPC(Remote Procedure Call Protocol)就是遠端呼叫,本質上是一種通訊方式。核心思想是將不同程序間的通訊抽象為函式呼叫,基本過程是呼叫端通過將引數序列化到流中併發送給服務端,服務端從流中反序列化出引數並完成實際處理,然後將結果序列化後返回給呼叫端。通常RPC通過介面來實現,介面定義服務名,介面方法定義每個請求的入參和結果。RPC內部的序列化、網路通訊等細節則由框架完成,對使用者完全透明。

3.索引在資料庫中有什麼作用?

  • 加快資料查詢(以空間換時間)
  • 資料庫中查詢最頻繁。索引是對資料庫表中一個或多個列的值進行排序的結構。與搜尋所有行相比,索引用指標指向儲存(在表中指定列)的資料,然後根據指定次序排列這些指標,有助於更快獲取資訊。通常經常查詢索引列時才需要在表上建立索引。索引將佔用磁碟空間,影響資料更新速度。但多數情況下索引帶來的速度優勢大大超過不足。
  • 主鍵、二級索引、覆蓋索引

4.面向物件的特徵有哪些方面?

  • 抽象:將一類物件的共同特徵總結出來構造成類,包括資料抽象和行為抽象。抽象只關注物件有哪些屬性和行為,不關注行為細節。
  • 繼承:從已有類得到繼承資訊建立新類的過程。提供繼承資訊的類被稱為父類(超類、基類);得到繼承資訊的類被稱為子類(派生類)。繼承讓程式有一定的延續性。
  • 封裝:封裝是把資料和操作資料的方法繫結起來,對資料訪問只通過已有介面。面向物件的本質就是將現實世界描繪成一系列物件。在類中編寫方法就是對實現細節的封裝;編寫一個類就是對資料和資料操作的封裝。封裝就是隱藏一切可隱藏的,只向外界提供最簡單的介面(可以想想普通洗衣機和全自動洗衣機的差別,明顯全自動洗衣機封裝更好操作更簡單;智慧手機也是封裝得足夠好,因為幾個按鍵(介面)就搞定所有事情)。
  • 多型性:多型性是指允許不同子型別的物件對同一訊息作出不同響應。簡單說是用同樣物件引用呼叫同樣方法但是做了不同事情。多型性分為編譯時多型性和執行時多型性。方法過載(overload)實現了編譯時多型性(也稱為前繫結),而方法重寫(override)實現了執行時多型性(也稱為後繫結)。執行時多型是面向物件最精髓的東西,要實現多型需要做兩件事:1). 方法重寫(子類繼承父類並重寫父類中已有的或抽象的方法);2). 物件造型(用父型別引用引用子型別物件,這樣同樣的引用呼叫同樣方法就會根據子類物件的不同而表現出不同行為)。

5.什麼是DAO模式?

  • DAO(Data Access Object)是一個為資料庫提供抽象介面的物件,在不暴露底層儲存細節的前提下提供各種資料訪問操作。
  • 實際開發中就是建立一個介面,將所有資料訪問操作抽象後封裝起來,當需要和資料來源互動時使用這個介面,並且編寫一個單獨的類來實現這個介面,在邏輯上該類對應一個特定的資料儲存。
  • DAO模式實際包含兩部分,一是解決如何訪問資料,二是解決如何用物件封裝資料。

6 voliatile修飾符有什麼作用?

voliatile變數的變更對任何執行緒都立即可見,可避免併發修改變數導致的資料不一致(機制:插入記憶體屏障,確保所有訪問者從主儲存中讀取資料,而不是從執行緒快取中讀取) 禁止指令重排序(JVM為加快程式執行做的優化,在單執行緒裡可提升效率,多執行緒時可能導致同步問題)

7解釋Synchronized關鍵字

  • synchronized是Java關鍵字,是一種同步鎖,它用來修飾一個方法或程式碼塊時,保證在同一時刻最多隻有一個執行緒執行該段程式碼:
  • 修飾方法,在方法宣告中加入 synchronized關鍵字來實現:每個類例項有一把鎖,每個 synchronized 方法都必須獲得呼叫該方法的類例項的鎖方能執行,否則所屬執行緒阻塞,方法一旦執行,就獨佔該鎖,直到從該方法返回時才將鎖釋放,此後被阻塞的執行緒方能獲得該鎖,重新進入可執行狀態。這種機制確保了同一時刻對於每一個類例項,其所有宣告為 synchronized的成員函式中至多隻有一個處於可執行狀態(因為至多隻有一個能夠獲得該類例項對應的鎖),從而避免了類成員變數的訪問衝突。
  • 修飾程式碼塊:synchronized 方法有缺陷:大方法宣告為synchronized會大大影響效率,Java為我們提供了更好的解決辦法,那就是 synchronized 塊。(實際就是對儘可能少的必要程式碼加鎖)
  • 不管是修飾方法還是程式碼塊,要取得的都是所在物件的鎖,而鎖定時間則看加鎖程式碼的執行效率。
  • 優化策略:讀多寫少的場景適合樂觀鎖、讀寫鎖(儘量不加鎖),高併發寫適合synchronized同步鎖。

8.什麼是執行緒區域性變數?

  • 侷限於執行緒內部的變數,為執行緒自身所有,不在多執行緒間共享。
  • Java 提供 ThreadLocal 類來支援執行緒區域性變數,是一種實現執行緒安全的方式。
  • 風險:需要合理的清理機制,比如web伺服器工作執行緒的生命週期比應用變數的生命週期要長。執行緒區域性變數一旦在工作完成後沒有釋放,Java 應用就存在記憶體洩露的風險。

9.解釋名詞:JRE、JDK、JVM 及 JIT

  • JRE 代表Java run-time,是執行Java引用所必須。
  • JDK 代表 Java 程式的開發工具,如 Java 編譯器,它也包含 JRE。
  • JVM 代表 Java 虛擬機器(Java virtual machine),責任是執行 Java 應用。
  • JIT 代表即時編譯(Just In Time compilation),當代碼執行次數超過一定閾值時,會將 Java 位元組碼轉換為原生代碼(熱點編譯),有利於提高 Java 應用效能。

10.值傳遞和引用傳遞

  • 值傳遞:方法呼叫時,實際引數把它的值傳遞給對應的形式引數,函式接收的是原始值的一個copy,此時記憶體中存在兩個相等的基本型別,即實際引數和形式引數,後面方法中的操作都是對形參這個值的修改,不影響實際引數的值。
  • 引用傳遞:方法呼叫時,實際引數的引用(記憶體地址)被傳遞給方法中的形式引數,函式接收實際引數的記憶體地址;形參和實參指向同一塊記憶體,方法執行中對引用的操作將影響到實際物件。
  • 基本資料型別使用傳值,對形參的修改不影響實參;引用型別傳引用,形參和實參指向同一記憶體地址,對引數的修改會影響到實際物件;不可變類(String,Integer等)由於自身特性,可以理解為傳值,最後操作不會修改實參物件

11.使用索引時的注意點

索引會大大提高資料檢索速率,也會降低更新表的速率,因為更新時需要額外更新索引 索引不會包含有NULL的列(資料庫設計時不要讓欄位預設值為NULL) 索引要精短(節省儲存,提升效率),對於長的索引欄位可使用字首擷取 like操作不推薦,使用的話,"%aaa%"不會使用索引,"aaa%"可以使用索引

12.說明虛擬機器是如何處理new關鍵字的?

1.首先檢查這個指令的引數是否能在常量區定位到一個類的引用,並檢查該類是否被載入 2.如果1不能滿足,先進行類載入操作 3.滿足1後,虛擬機器將為新生物件分配記憶體(指標碰撞-空閒列表) 4.分配萬記憶體後,對記憶體做初始化 5.虛擬機器設定物件的資訊,hash、GC資訊等。—新物件至此完全生成

13.簡要說明類載入的過程

將class檔案載入到記憶體,並對資料做校驗、解析、初始化,最終轉化為虛擬機器可以直接使用的java型別,在程式執行過程中完成 觸發類載入的時機:1-new關鍵字,呼叫/讀取類的靜態方法/欄位;2-使用java.lang.reflect對類做反射呼叫時;3-初始化類時,先初始化父類 1.載入:1.1-通過類的全限定名獲取定義該類的二進位制位元組流;1.2-將二進位制位元組流代表的靜態儲存結構轉換為方法區的執行時資料結構;1.3-在記憶體中生成java.lang.Class物件,作為對該類的訪問入口 2.驗證:確保class檔案的位元組流包含資訊符合虛擬機器的要求 3.準備:為類變數分配記憶體並設定類變數初始值(不包括例項變數–例項變數隨物件一塊分配在堆中) 4.解析:將常量池中的符號引用替換為直接引用 5.初始化:類載入的最後一步,開始執行java程式的程式碼–執行類構造器的()方法

14.簡述https建立連線的過程

1.客戶端瀏覽器發出安全請求(https字首) *2.服務端傳送數字證書(包含伺服器的publicKey) * 3.客戶端使用預置的CA列表驗證證書,如果有問題則提示風險 4.客戶端生成隨機的對稱金鑰,用伺服器的publicKey加密 5.伺服器用自己的privateKey解密,得到對稱金鑰 6.雙方都使用對稱金鑰加密通訊

數字證書的原理: (1){RSA(hash(message))+message} (message中包含publicKey)(前半部分為數字簽名sign) (2)比對reRSA(sign) == hash(message) (3)reRSA使用CA的公鑰來解密

15.簡述虛擬機器中例項物件的建立過程

1.從位元組碼中獲取目標物件在常量池的索引 2.根據索引獲取常量池中的類資料 3.如果滿足類的快速分配條件,則進行快速分配(2.1開始TLAB時嘗試在TLAB中分配,2.2無法進行TLAB分配則持續嘗試在EDEN區分配,直至分配成功) 4.無法做快速分配,則使用慢速分配(確保類不是抽象類,做類初始化並分配例項) 5.例項分配完成後,設定執行緒棧頂的物件引用

16.java註解

即元資料:描述資料A(類、方法、變數等)的資料B,對資料A做宣告,然後通過反射獲取描述資訊,並根據描述資訊的條件來執行資料A @Override:在編譯階段生效,編譯的時候編譯器會檢查使用@Override修飾的方法是否和父類方法簽名(方法名+引數)相同,如果不同則報錯 使用場合:與java原始碼寫在一塊,簡單直觀,不過註解散佈在程式碼各處,有時不易維護,對於需要集中配置的場合,則推薦使用XML配置(如mybatis的資料來源配置) 自定義註解:測試 @Test

@Retention(RetentionPolicy.RUNTIME)
@Target(ElmentType.METHOD)
public @interface Test(){
    boolean ignore() default false;
}

public class AaTest{
    @Test
    public int test1(){
        return 1;
    }
    @Test(ignore=true)
    public int test2(){
        return 2;
    }
}

public static void main(String [] args){
    AaTest tt = new AaTest();
    run(tt);
}

public static void run(Object obj){
    for(Method m : obj.getClass().getMethods()){
        Test t = m.getDeclaredAnnoation(Test.class);
        if(t!=null && !t.ignore()){
            m.invoke(obj);
        }
    }
}

16.cookie—session—token

目的:解決http無連線的問題,提供連線中繼;安全性 cookie:快取http登入資訊等,儲存在客戶端,client與服務端通訊時服務端根據cookie解析出資料(有失效期) session:服務端分配給客戶端,客戶端通訊時加上session,服務端比對自己儲存的session,一致則認為是同一請求—session需要集中儲存(儲存在服務端或者分散式快取),儲存壓力大 token:服務端給客戶端分配token,接收請求時根據token用金鑰生成簽名,與token中的簽名比對即可—不要專門儲存token,每次使用演算法計算