感謝牛客網!
Java基礎知識
- HashTable、HashMap、ConcurrentHashMap 底層實現 ,hashmap的hash計算方式?爲什麼要右移16位?HashMap擴容? ConcurrentHashMap統計數據總量時的流程?put的流程,get流程、併發問題分析、哈希衝突、作爲HashMap的key需要做什麼?TreeMap是通過紅黑樹實現的 ,HashSet底層爲HashMap,存的value默認都爲一個常量Object對象,名稱爲PRESENT。ConcurrentHashMap 1.8以後爲CAS+同步鎖,1.7以前爲分段鎖。
HashMap爲何設置鏈表達到8個、且數組長度到達64就轉紅黑樹? 答:1、TreeNodes(紅黑樹)佔用空間是普通Nodes(鏈表)的兩倍,爲了時間和空間的權衡。2、節點的分佈頻率會遵循泊松分佈,鏈表長度達到8個元素的概率爲0.00000006,幾乎是不可能事件。爲什麼轉化爲紅黑樹的閾值8和轉化爲鏈表的閾值6不一樣:是爲了避免頻繁來回轉化。(13次)
HashMap的構造方法及第一次put時的擴容操作
put( ): 非首次put - Synchronized 的鎖,Synchronized加鎖流程?syn爲什麼效率低? Synchronized是重量級的鎖嗎?能實現輕量鎖嗎?Synchronized是不是可重入鎖?synchronized和lock區別?Synchronized用在靜態和非靜態方法的區別?(9次)
(1)synchronized和Lock都具備可重入性。(重入鎖是可重複獲得資源的鎖,已經獲得鎖的線程可以對當前的資源重入加鎖而不會引起阻塞;不可重入鎖是不可重複獲得資源的鎖,當已經獲得鎖的線程對當前資源再次加鎖時,會把自己阻塞。)(2)synchronized不是可中斷鎖,而Lock是可中斷鎖。(3)synchronized是非公平鎖,而對於ReentrantLock和ReentrantReadWriteLock,它默認情況下是非公平鎖,但是可以設置爲公平鎖,ReentrantLock lock = new ReentrantLock(true); 如果參數爲true表示爲公平鎖,爲fasle爲非公平鎖。 - 垃圾回收算法,GC算法、分代收集、如何判斷一個對象是否可回收?垃圾回收的優缺點?爲什麼默認使用G1垃圾收集器? (7次)
- jdk1.7 默認垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
- jdk1.8 默認垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
- jdk1.9 默認垃圾收集器G1,G1跟蹤各個Region獲得其收集價值大小,在後臺維護一個優先列表;每次根據允許的收集時間,優先回收價值最大的Region
常用GC算法: 標記清除算法、複製算法 (新生代)、標記整理算法 (老年代)、分代收集算法
判斷對象是否死亡: - 引用計數法。無法解決對象之間相互循環引用的問題。
- 可達性分析法。可以作爲GC Root的有:1、虛擬機棧(棧幀中的本地變-量表)中引用的對象。2、方法區中類靜態屬性引用的對象。3、方法區中常量引用的對象。4、本地方法棧中 JNI(即一般說的 Native 方法)引用的對象
7種垃圾收集器
- BIO、NIO、AIO,Netty線程機制,protoBuf和其他序列化框架的對比、IO模型 select poll epoll區別 (7次)
- BIO: 同步阻塞式IO。應用進程被阻塞,直到數據從內核緩衝區複製到應用進程緩衝區中才返回。
- NIO: 同步非阻塞式IO。應用進程執行系統調用之後,內核返回一個錯誤碼。應用進程可以繼續執行,但是需要不斷的執行系統調用來獲知 I/O 是否完成,這種方式稱爲輪詢。
- AIO:異步非堵塞的 IO 操作方式,異步 IO 是基於事件和回調機制實現的,也就是應用操作之後會直接返回,不會堵塞在那裏,當後臺處理完成,操作系統會通知相應的線程進行後續的操作。
- I/O 多路複用 的特點是通過一種機制一個進程能同時等待多個文件描述符,這一過程會被阻塞,而這些文件描述符(套接字描述符)其中的任意一個進入讀就緒狀態,select()函數就可以返回。它可以讓單個進程具有處理多個 I/O 事件的能力。
- 信號驅動IO: 應用進程使用 sigaction 系統調用,內核立即返回,應用進程可以繼續執行,也就是說等待數據階段應用進程是非阻塞的。內核在數據到達時嚮應用進程發送 SIGIO 信號,應用進程收到之後在信號處理程序中調用 recvfrom 將數據從內核複製到應用進程中。異步 I/O 與信號驅動 I/O 的區別在於,異步 I/O 的信號是通知應用進程 I/O 完成,而信號驅動 I/O 的信號是通知應用進程可以開始 I/O。
select,poll,epoll都是IO多路複用的機制。 - select :調用後select函數會阻塞,直到有描述符就緒(有數據 可讀、可寫、或者有except),或者超時(timeout指定等待時間,如果立即返回設爲null即可),函數返回。當select函數返回後,通過遍歷所有描述符,來找到就緒的描述符。select目前幾乎在所有的平臺上支持,其良好跨平臺支持也是它的一個優點。select的一 個缺點在於單個進程能夠監視的文件描述符的數量存在最大限制,文件描述符存儲使用數組實現,在Linux上一般爲1024。
- poll :select和poll都需要在返回後,通過遍歷文件描述符來獲取已經就緒的socket。poll 沒有描述符數量的限制;
- epoll :通過回調函數內核會將 I/O 準備好的描述符加入到一個鏈表中管理,進程調用 epoll_wait() 便可以得到事件完成的描述符,進程不需要通過輪詢來獲得事件完成的描述符。epoll 僅適用於 Linux OS。epoll 比 select 和 poll 更加靈活而且沒有描述符數量限制。epoll工作模式: LT 模式:當 epoll_wait() 檢測到描述符事件到達時,將此事件通知進程,進程可以不立即處理該事件,下次調用 epoll_wait() 會再次通知進程。是默認的一種模式;ET 模式: 通知之後進程必須立即處理事件,下次再調用 epoll_wait() 時不會再得到事件到達的通知。
- 應用場景: select 的 timeout 參數精度爲微秒,而 poll 和 epoll 爲毫秒,所以select 更加適用於實時性要求比較高的場景,比如核反應堆的控制;poll 沒有最大描述符數量的限制,如果平臺支持並且對實時性要求不高,應該使用 poll 而不是 select;epoll只需要運行在 Linux 平臺上,有大量的描述符需要同時輪詢,並且這些連接最好是長連接。
- 文件描述符:在linux系統中打開文件就會獲得文件描述符,它是個很小的非負整數。每個進程在PCB中保存着一份文件描述符表,文件描述符就是這個表的索引,每個表項都有一個指向已打開文件的指針。
- JVM類加載機制 延伸:父類和子類中都有靜態變量、靜態代碼塊、非靜態變量、構造函數。new這個子類的時候,以上四個執行順序是什麼樣的? 順序爲:父類靜態變量 --> 父類靜態代碼塊 --> 子類靜態變量 --> 子類靜態代碼塊 --> 父類非靜態代碼塊 --> 父類構造函數 --> 子類非靜態代碼塊 --> 子類構造函數
類加載過程:
- 加載: 通過類的完全限定名稱獲取定義該類的二進制字節流。將該字節流表示的靜態存儲結構轉換爲方法區的運行時存儲結構。在內存中生成一個代表該類的 Class 對象,作爲方法區中該類各種數據的訪問入口。
- 驗證 確保 Class 文件的字節流中包含的信息符合當前虛擬機的要求,並且不會危害虛擬機自身的安全。
- 準備 準備階段爲類變量分配內存並設置初始值,使用的是方法區的內存,類變量是被 static 修飾的變量。
- 解析 將常量池的符號引用替換爲直接引用的過程。符號引用與虛擬機實現的內存佈局無關,引用的目標並不一定已經加載到內存中。直接引用可以是直接指向目標的指針,是和虛擬機實現的內存佈局相關的,引用的目標必定已經在內存中存在。
- 初始化 初始化階段是虛擬機執行類構造器 () 方法的過程。根據程序員通過程序制定的主觀計劃去初始化類變量和其它資源。
雙親委派模式?啓動類加載器 --> 擴展類加載器 --> 應用程序類加載器 --> 自定義類加載器(4次)
-
JVM內存模型 、JVM內存區域劃分、堆中的異常,棧中的異常(4次)
-
ThreadLocal 原理、使用場景、內存泄漏 (4次)
ThreadLocal提供了線程內存儲變量的能力,這些變量不同之處在於每一個線程讀取的變量是對應的互相獨立的。ThreadLocal的靜態內部類ThreadLocalMap爲每個Thread都維護了一個Entry<key, value>型數組table,key存儲線程本地對象,value爲線程的變量副本,key爲弱引用(生命週期只能存活到下次GC前),value並非弱引用。在調用ThreadLocal的get()、set()方法時完成後再調用remove方法可避免內存泄漏。每個ThreadLocal實例在table中的索引i是不同的。ThreadLocal的典型場景正如上面的數據庫連接管理,線程會話管理等場景 -
設計模式:工廠模式、單例模式、適配器模式、懶漢模式、惡漢模式、觀察者模式 、每種模式的問題(4次)
-
線程池原理、線程池的好處、如何確定線程池大小(3次)
-
java又是怎麼保證線程同步(安全)的呢?volatile 可見性原理 ,volatile不保證原子性是爲啥?(3次)
volatile:1、保證了不同線程對這個變量進行操作時的可見性,即一個線程修改了某個變量的值,這新值對其他線程來說是立即可見的。(實現可見性)2、禁止進行指令重排序。(實現有序性)3、volatile 只能保證對單次讀/寫的原子性。i++ 這種操作不能保證原子性。 -
內存泄漏原因、舉例子、如何排查內存泄漏的原因(2次)
-
重載與重寫 、 多態。 (2次)
1、重寫:(1)方法名、參數列表必須完全與被重寫方法的相同。(2)返回類型與被重寫方法的返回類型必須兼容,即返回值必須類型相同,或子類返回值必須是父類返回值的派生類(java5 及更早版本返回類型要一樣,java7 及更高版本可以不同)。(3)重寫方法不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的異常。(4)訪問權限不能比父類中被重寫的方法的訪問權限更低。例如:如果父類的一個方法被聲明爲 public,那麼在子類中重寫該方法就不能聲明爲 protected。(5)聲明爲 final 的方法不能被重寫。(6)構造方法不能被重寫。
2、重載:(1)方法名必須相同、參數的數量不同,或順序不同(參數類型不同時),或參數類型不同 都是重載。(2)不能根據返回類型區分重載,返回類型可以相同也可以不同。(3)被重載的方法可以改變訪問修飾符;(4)被重載的方法可以聲明新的或更廣的檢查異常。
3、在編譯階段,只是檢查參數的引用類型。然而在運行時,Java 虛擬機(JVM)指定對象的類型並且運行該對象的方法。
4、方法重載是一個類的多態性表現,而方法重寫是子類與父類的一種多態性表現。
Java重載與重寫 -
collection 和 Collections的區別 (2次)
-
List、Set :List是不是有序的,能不能重複,ArrayList和LinkedList區別、List中如何刪除元素:迭代器、爲什麼不能在遍歷list的時候刪除其中的元素呢(2次)
-
==和equals的區別? (2次)
1、兩個對象用equals()比較返回true,那麼兩個對象的hashCode()方法必須返回相同的結果。
2、兩個對象用equals()比較返回false,不要求hashCode()方法也一定返回不同的值,但是最好返回不同值,以提高哈希表性能。
3、重寫equals()方法,必須重寫hashCode()方法,以保證equals方法相等。 -
抽象類與接口的聯繫與區別?(2次)
有抽象方法的類一定是抽象類,抽象類中的方法可以不是抽象的;
參數 | 抽象類 | 接口 |
---|---|---|
構造器 | 抽象類可以有構造器 | 接口不能有構造器 |
成員變量 | 可以有普通成員變量 | 接口中定義的變量只是public static final 類型,並且默認即爲 public static final 類型,並且需要給出初始值 |
方法 | 可以包含非抽象的普通方法 | 所有方法必須都是抽象的 |
靜態方法 | 可以包含靜態方法 | 不能包含靜態方法 |
方法訪問類型 | 抽象方法可以有public、protected和default這些修飾符 | 接口方法默認修飾符是public。你不可以使用其它修飾符。 |
實現 | 子類使用extends關鍵字來繼承抽象類。如果子類不是抽象類的話,它需要提供抽象類中所有聲明的方法的實現 | 子類使用關鍵字implements來實現接口。它需要提供接口中所有聲明的方法的實現 |
- JDK動態代理和Cglib代理的區別、底層是怎麼實現的、哪個性能更好、cglib代理和jdk動態代理的優缺點? (2次)
反射: JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法;這種動態獲取的以及動態調用對象的方法的功能稱爲java語言的反射機制。
Java動態代理的優勢是實現無侵入式的代碼擴展,也就是方法的增強;讓你可以在不用修改源碼的情況下,增強一些方法;在方法的前後你可以做你任何想做的事情。
- JDK動態代理
- 通過實現 InvocationHandler 接口,重寫invoke方法創建自己的調用處理器類;
- 通過爲 Proxy 類指定 ClassLoader 對象和一組 interface 、調用處理器類的對象實例來創建動態代理類;
HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);
其中的3個參數通過反射機制獲得:被代理的類的類加載器、被代理類的接口數組、調用處理器類的對象實例; - 優點 :Java原生支持的動態代理,無需外部依賴。 缺點:被JDK動態代理的類一定要是實現了某個接口的,如果有些類並沒有實現接口,則不能使用JDK代理,這時就要使用cglib動態代理了。
- cglib動態代理
- cglib動態代理類需要實現MethodInterceptor接口重寫intercept方法
- 通過
enhancer.setSuperclass(this.target.getClass());
對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因爲採用的是繼承,所以不能對final修飾的類進行代理。 - 優點: 無論目標對象有沒有實現接口都可以代理。缺點: 不能對final修飾的類進行代理。
java動態代理(JDK和cglib)
- 一致性hash (1次)一致性哈希
- 鎖升級的過程? (1次)
- 偏向鎖: 當一個線程訪問同步代碼塊並獲取鎖時,會在Mark Word裏存儲鎖偏向的線程ID。偏向鎖是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖,降低獲取鎖的代價。
- 輕量級鎖: 當鎖是偏向鎖的時候,被另外的線程所訪問,偏向鎖就會升級爲輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,從而提高性能。若當前只有一個等待線程,則該線程通過自旋進行等待。針對的是多個線程在不同時間段申請同一把鎖的情況
- 重量級鎖: 當自旋超過一定的次數,或者一個線程在持有鎖,一個在自旋,又有第三個來訪時,輕量級鎖升級爲重量級鎖。針對的是多個線程同時競爭同一把鎖的情況。
- 非公平鎖和公平鎖?優缺點?非公平鎖搶佔流程? (1次)
- 釋放鎖的流程? (1次)
- Java併發,併發並行的區別 (1次)
- CountDownLatch和CyclicBarrier使用過嗎?什麼原理? (1次)
- 深拷貝淺拷貝的區別?
淺拷貝: 1) 對於基本數據類型的成員對象,因爲基礎數據類型是值傳遞的,所以是直接將屬性值賦值給新的對象。基礎類型的拷貝,其中一個對象修改該值,不會影響另外一個。(2) 對於引用類型,比如數組或者類對象,因爲引用類型是引用傳遞,所以淺拷貝只是把內存地址賦值給了成員變量,它們指向了同一內存空間。改變其中一個,會對另外一個也產生影響。
深拷貝: (1) 對於基本數據類型的成員對象,因爲基礎數據類型是值傳遞的,所以是直接將屬性值賦值給新的對象。基礎類型的拷貝,其中一個對象修改該值,不會影響另外一個(和淺拷貝一樣)。(2) 對於引用類型,比如數組或者類對象,深拷貝會新建一個對象空間,然後拷貝里面的內容,所以它們指向了不同的內存空間。改變其中一個,不會對另外一個也產生影響。(3) 對於有多層對象的,每個對象都需要實現 Cloneable 並重寫 clone() 方法,進而實現了對象的串行層層拷貝。(4) 深拷貝相比於淺拷貝速度較慢並且花銷較大。
淺拷貝: 直接調用父類的clone()方法
public class Student implements Cloneable {
//引用類型
private Subject subject;
@Override
public Object clone() {
//淺拷貝
try {
// 直接調用父類的clone()方法
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
深拷貝: (1)對於有多層對象的,每個對象都需要實現 Cloneable 並重寫 clone() 方法,進而實現了對象的串行層層拷貝。(2)使用序列化。
public class Subject implements Cloneable {
private String name;
@Override
protected Object clone() throws CloneNotSupportedException {
//Subject 如果也有引用類型的成員屬性,也應該和 Student 類一樣實現
return super.clone();
}
}
public class Student implements Cloneable {
//引用類型
private Subject subject;
public Object clone() {
//深拷貝
try {
// 直接調用父類的clone()方法
Student student = (Student) super.clone();
student.subject = (Subject) subject.clone();
return student;
} catch (CloneNotSupportedException e) {
return null;
}
}
}
Java 淺拷貝和深拷貝(1次)
25. string幾種拼接方式區別,+和append底層有沒有區別 (1次)
26. 怎麼優化才能既不用加鎖又能提高併發訪問的效率?(1次)
27. 如何控制這個程序使其佔用的內存不能超過6G呢? (1次)
28. 爲什麼要引入雙親委派機制 (1次)
29. JVM的啓動參數有哪些?在jvm上運行一段java程序輸出一條語句,它是怎麼輸出到屏幕上的? (1次)
30. 對於一個容器,比如set,你想實現自定義排序規則的話怎麼做 (1次)
31. CAS底層實現、CAS造成的問題 (1次)
32. UTF-8和utf8mb4的區別 (1次)
33. Java爲什麼生成字節碼 (1次)
34. 知道const嗎?詳細說說 (1次)
35. String、StringBuffer、StringBuilder三者的區別? (1次)
36. hashset容器下的分類及各自特點? (1次)
37. 講一講你對hashcode和equal這兩個函數的認識 (1次)
38. comparator排序 (1次)
39. 強引用、軟引用、弱引用、虛引用? (1次)
- 強引用: 被強引用關聯的對象不會被回收。使用 new 一個新對象的方式來創建強引用。
- 軟引用: 被軟引用關聯的對象只有在內存不夠的情況下才會被回收。使用 SoftReference 類來創建軟引用。
- 弱引用: 被弱引用關聯的對象一定會被回收,也就是說它只能存活到下一次垃圾回收發生之前。使用 WeakReference 類來創建弱引用。
- 虛引用: 一個對象是否有虛引用的存在,不會對其生存時間造成影響。設置虛引用的唯一目的是能在這個對象被回收時收到一個系統通知。
- Java的線程狀態:
-
New:新創建的線程,尚未執行;
-
Runnable:運行中的線程,正在執行run()方法的Java代碼;
-
Blocked:運行中的線程,因爲某些操作被阻塞而掛起;
-
Waiting:進入該狀態的線程需要等待其他線程做出一些特定動作(通知或中斷)。
-
Timed Waiting:該狀態不同於Waiting,它可以在指定的時間後自行返回。
-
Terminated:線程已終止,因爲run()方法執行完畢。
Thread.sleep和Object.wait()的區別:
- sleep來自Thread類,和wait來自Object類。
- sleep方法沒有釋放鎖,而wait方法釋放了鎖:sleep不出讓系統資源;wait是進入線程等待池等待,出讓系統資源,其他線程可以佔用CPU。
- Thread.Sleep(0)的作用是“觸發操作系統立刻重新進行一次CPU競爭”。Object.wait()一般不指定時間。
- wait,notify和notifyAll只能在同步控制方法或者同步控制塊裏面使用,要等待其他線程調用notify/notifyAll喚醒等待池中的所有線程,纔會進入就緒隊列等待OS分配系統資源。而sleep可以在任何地方使用。
- Integer和int的區別? (1次)
1、Integer是int的包裝類,int則是java的一種基本數據類型 2、Integer變量必須實例化後才能使用,而int變量不需要 3、Integer實際是對象的引用,當new一個Integer時,實際上是生成一個指針指向此對象;而int則是直接存儲數據值 4、Integer的默認值是null,int的默認值是0
int和Integer的區別 - 繼承和組合的區別以及優缺點? (1次)
- 繼承: 繼承就是子類繼承父類的特徵和行爲,使得子類對象(實例)具有父類的實例域和方法。優點:支持擴展,通過繼承父類實現,但會使系統結構較複雜;易於修改被複用的代碼。缺點: 代碼白盒複用,父類的實現細節暴露給子類,破壞了封裝性;子類缺乏獨立性,依賴於父類,耦合度較高;當父類的實現代碼修改時,可能使得子類也不得不修改,增加維護難度。
- 組合: 組合是通過對現有對象進行拼裝即組合產生新的具有更復雜的功能。優點: 代碼黑盒複用,被包括的對象內部實現細節對外不可見,封裝性好;整體類與局部類之間松耦合,相互獨立。缺點: 創建整體類對象時,需要創建所有局部類對象。導致系統對象很多。
繼承和組合的區別
- 原子類保證原子操作的原理? (1次)
原子類主要利用 CAS + volatile 和 native 方法來保證原子操作,從而避免 synchronized 的高開銷,執行效率大爲提升。 - finalize()是Object中的方法,當垃圾回收器將要回收對象所佔內存之前被調用,即當一個對象被虛擬機宣告死亡時會先調用它finalize()方法,讓此對象處理它生前的最後事情。 (1次)
- Java作用域有哪些? (1次)
計算機網絡知識
- TCP四次揮手爲什麼是四次,三次握手 爲什麼不是兩次(4次)
- 兩次握手的話: 如客戶端發出連接請求,但因連接請求報文丟失而未收到確認,於是客戶端再重傳一次連接請求。後來收到了確認,建立了連接。
數據傳輸完畢後,就釋放了連接,客戶端共發出了兩個連接請求報文段,其中第一個丟失,第二個到達了服務端,但是第一個丟失的報文段只是在某些網絡結點長時間滯留了,延誤到連接釋放以後的某個時間纔到達服務端,此時服務端誤認爲客戶端又發出一次新的連接請求,於是就向客戶端發出確認報文段,同意建立連接,不採用三次握手,只要服務端發出確認,就建立新的連接了,此時客戶端忽略服務端發來的確認,也不發送數據,則服務端一致等待客戶端發送數據,浪費資源。
- UDP/TCP區別,TCP如何可靠傳輸,擁塞控制如何實現、擁塞窗口和滑動窗口的使用 (4次)
- 什麼時候應該使用TCP:
當對網絡通訊質量有要求的時候,比如:整個數據要準確無誤的傳送給對方,這往往用於一些可靠的應用,比如HTTP,HTTPS,FTP等傳輸文件的協議,POP,SMTP等郵件傳輸的協議。 - 什麼時候使用UDP:
當對網絡通訊質量要求不高的時候,要求網絡通訊速度能儘量的快,這時就可以使用UDP。常見使用UDP協議的應用如下:QQ語音,QQ視頻,TFTP等。
- TCP三次握手和四次揮手的詳細過程 (3次)TCP的三次握手與四次揮手
- http協議,http報頭 (2次)HTTP協議超詳細解析
- 網頁輸入一個url都發生了什麼?DNS->IP->TCP->HTTP->ARP->MAC (2次)
1、瀏覽器查找域名的IP地址,DNS域名解析(先遞歸查詢、後迭代查詢)。
2、根據默認端口80,通過3次握手建立TCP連接。
3、瀏覽器給web服務器發送一個HTTP請求
4、服務器對瀏覽器的請求做出響應,並把對應的HTML文本發送給瀏覽器。
5、關閉TCP連接。
6、瀏覽器解析HTML,渲染展示給用戶。
輸入URL(如www.baidu.com)會發生什麼 - 視頻用UDP還是TCP 爲什麼 (1次)
- HTTP 1.0/1.1/2.0的區別以及http和https的區別(2次)解答1、解答2
- ssl層作用 證書有什麼用 (1次)
- 常見錯誤碼(301、302、500、404、403) (1次)
- SYN泛洪攻擊 (1次)SYN攻擊利用的是TCP的三次握手機制,攻擊端利用僞造的IP地址向被攻擊端發出請求,而被攻擊端發出的響應 報文將永遠發送不到目的地,那麼被攻擊端在等待關閉這個連接的過程中消耗了資源,如果有成千上萬的這種連接,主機資源將被耗盡,從而達到攻擊的目的。
- 談下你對servlet的認識?(好像重點要知道它是單例的) (1次)
- 七層網絡協議和四層網絡協議的區別 (1次)
- 講講restful(面向資源,一個資源一個url,http層,四種操作) (1次)
- htttps 的加密方式(我說了一個ssl,因爲沒用過,所以也沒法細說) (1次)
SSL協議握手過程:
- 客戶端給出協議版本號、一個客戶端生成的隨機數(Client random),以及客戶端支持的加密方法。
- 服務端確認雙方使用的加密方法,並給出數字證書、以及一個服務器生成的隨機數(Server random)。
- 客戶端確認數字證書有效,然後生成一個新的隨機數(Premaster secret),並使用數字證書中的公鑰,加密這個隨機數,發給服務端。
- 服務端使用自己的私鑰,獲取客戶端發來的隨機數(即Premaster secret)。
- 客戶端和服務端根據約定的加密方法,使用前面的三個隨機數,生成"對話密鑰"(session key),用來加密接下來的整個對話過程。
參考:圖解SSL/TLS協議
- http端口:80?https端口:443 (1次)
- 如何實現可靠的UDP? (1次)簡單來講,要使用UDP來構建可靠的面向連接的數據傳輸,就要實現類似於TCP協議的超時重傳,有序接受,應答確認,滑動窗口流量控制等機制,等於說要在傳輸層的上一層(或者直接在應用層)實現TCP協議的可靠數據傳輸機制,比如使用UDP數據包+序列號,UDP數據包+時間戳等方法,在服務器端進行應答確認機制
- post 和get的區別?(1次)
get | post | |
---|---|---|
可見性 | 數據在 URL 中對所有人都是可見的。 | 數據不會顯示在 URL 中。 |
安全性 | 與 POST 相比,GET 的安全性較差,因爲所發送的數據是 URL 的一部分。 | POST 比 GET 更安全,因爲參數不會被保存在瀏覽器歷史或 web 服務器日誌中。 |
緩存 | 能被緩存 | 不能被緩存 |
對數據長度的限制 | 是的。當發送數據時,GET 方法向 URL 添加數據;受瀏覽器對URL長度的限制的(IE的URL 的最大長度是 2048 個字符)。 | 受web服務器對post數據處理長度的限制,可設置爲無限制 |
書籤 | 可收藏爲書籤 | 不可收藏爲書籤 |
- TCP粘包原因?(1次)答:1、發送端需要等緩衝區滿才發送出去,造成粘包(發送數據時間間隔很短,數據了很小,會合到一起,產生粘包)2、接收方不及時接收緩衝區的包,造成多個包接收(客戶端發送了一段數據,服務端只收了一小部分,服務端下次再收的時候還是從緩衝區拿上次遺留的數據,產生粘包) 。總結:接收方不知道該接收多大的數據纔算接收完畢,造成粘包。
粘包解決方案?答:1、分兩次通訊分別傳遞內容大小和內容。2、一次通訊直接傳遞內容大小和內容,把報頭做成字典,字典裏包含將要發送的真實數據的詳細信息,然後json序列化。 - session和cookie的區別?
1、存儲位置不同: cookie數據存放在客戶的瀏覽器上,session數據放在服務器上。
2、存儲容量不同: 單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。對於Session並沒有上限,但出於對服務器端的性能考慮,Session內不要存放過多的東西,並設置session刪除機制。
3、存取方式不同: cookie中只能保管ASCII字符串,並需要通過編碼方式存儲爲Unicode字符或者二進制數據。session中能夠存儲任何類型的數據,包括且不限於string,integer,list,map等。
4、隱私策略不同: Cookie對客服端是可見的,別有用心的人可以分析放在本地的Cookie上面並進行Cookie欺騙,所以它是不安全的。
5、有效期不同: 開發可以通過設置Cookie的屬性,達到Cookie長期有效的效果,只要關閉窗口該Session就會失效,因爲假如設置Session的超過時間過長,服務器累計的Session就會越多,越容易導致內存溢出。
6、跨域支持上的不同: Cookie 支持跨域名訪問,例如,將 domain 屬性設置爲“.biaodianfu.com”,則以“.biaodianfu.com”爲後綴的一切域名均能夠訪問該Cookie。Session則不會支持跨域名訪問。Session僅在它所在的域名內有效。
Cookie和Session區別 - 如果客戶端禁用了cookie,怎麼使用session? (1次)
(1)使用URL重寫,將sessionid附在URL的後面,傳給服務器。
(2)表單隱藏字段,服務器會自動修改表單,添加一個隱藏字段,以便在表單提交時能夠把sessionid傳回服務器。 - 服務端出現大量TIME_OUT?解決? (1次)
答:在高併發短連接的TCP服務器上,當服務器處理完請求後立刻主動正常關閉連接。這個場景下會出現大量socket處於TIME_WAIT狀態。短連接表示“業務處理+傳輸數據的時間 遠遠小於 TIMEWAIT超時的時間”的連接。解決:編輯內核文件/etc/sysctl.conf 打開系統的TIMEWAIT重用和快速回收。 - session默認失效時間?(1次) 30min
MySQL、數據庫
- 存儲的數據結構、索引類型、索引底層、 B+樹與B-樹的區別 、索引是怎麼提高效率的、B+ 樹和B樹、紅黑樹,爲什麼MySql索引使用B+樹、B+樹作爲索引有什麼缺點、“like”查詢在什麼時候能夠用上索引(7次)
- 哈希雖然能夠提供 O(1) 的單數據行操作性能,但是對於範圍查詢和排序卻無法很好地支持,最終導致全表掃描;
- B 樹能夠在非葉節點中存儲數據,但是這也導致在查詢連續數據時可能會帶來更多的隨機 I/O,而 B+ 樹的所有葉節點可以通過指針相互連接,能夠減少順序遍歷時產生的額外隨機 I/O;
- Innodb、Myisam 區別、引擎選型,不同引擎的索引類型、存儲日誌,用什麼存儲引擎比較合適 (4次)
- 常見的鎖(表鎖、行鎖)及功能 ,鎖的粒度劃分以及原理、性能、使用時注意事項。(2次)
- 什麼是慢查詢?怎麼解決? (1次)
- 主鍵索引和普通索引 (1次)
- 存儲日誌文件(一般來說日誌文件只有在出錯的時候纔會去看它,平時基本上不會去查)應該如何設計索引的數據結構? (1次)
- ACID 原子性、一致性、隔離性、可持續性 (1次)
- mysql提高讀取效率得方式? 索引,分表分區 (1次)
- 什麼是事務 (1次) 事務是數據庫操作的最小工作單元,是作爲單個邏輯工作單元執行的一系列操作;這些操作作爲一個整體一起向系統提交,要麼都執行、要麼都不執行;事務是一組不可再分割的操作集合(工作邏輯單元)
- 索引io是什麼io模型,爲什麼? (1次)
- MySQL的主從複製原理,如何實現 (1次)
- 數據庫中一行記錄大小10K,一個表只有主鍵索引,可以存多少條數據 (1次)
- 數據庫一個表中最多可以插入多少數據 (1次)
- 數據庫中存儲密碼是怎麼存的(MD5加密),還知道其他加密方式嗎? 一個6位的密碼,使用MD5加密,破解需要多久:說的是這樣的,因爲6位的密碼排列組合有一定的種數,然後每一種通過hash函數去破解,需要多久 (1次)
- 悲觀鎖,樂觀鎖在數據庫中如何實現的 (1次)
- sql注入攻擊瞭解嗎?講講你對它的理解?那如何解決? (1次)
- 談談你對數據庫中join操作的理解 (1次)
- 你瞭解數據庫中可重複讀隔離級別如何實現嗎? (1次)(MVCC) MVCC其實在MySQL可重複讀的隔離級別中並不是完全解決了幻讀的問題,而是解決了讀數據情況下的幻讀問題。而對於修改的操作依舊存在幻讀問題。
next-key鎖(行鎖+間隙鎖)可以解決幻讀。當索引爲唯一索引時,next-key鎖自動優化爲行鎖,行鎖鎖定的是索引,而不是行數據,也就是說鎖定的是key。
透徹解讀mysql的可重複讀、幻讀及實現原理
Next-Key Lock 淺談 - 快照讀,當前讀? (1次)讀取歷史數據的方式,我們叫它快照讀 (snapshot read),當執行select操作時innodb默認會執行快照讀;而讀取數據庫最新版本數據的方式,叫當前讀 (current read),對於會對數據修改的操作(update、insert、delete)都是採用當前讀的模式
- JDBC (1次)
- 數據庫查詢很慢,如何優化,問到具體查詢索引性能的sql語句 (1次)
- 回表? (1次)
- 估算一下,一張表字段有多少字節? 一行大小最大爲65535字節(1次)
- char和varchar的區別和細節?(1次)CHAR和VARCHAR有哪些區別?
- join用法:
- 刪除表中除主鍵外完全重複的數據,保留id最小的那一條數據 (1次)
DELETE t1
from t_a t1, t_a t2
WHERE t1.mail=t2.mail and t1.name=t2.name and t1.id>t2.id;
- 索引失效的原因? (1次)
1、有or必須所有條件都有索引纔會用索引; 2、複合索引未用左列字段; 3、like以%開頭; 4、需要類型轉換; 5、where中索引列有運算; 6、where中索引列使用了函數; 7、如果mysql覺得全表掃描更快時(數據少); - Mysql分頁查詢實現:
使用limit 參數1,參數2; 參數1爲開始查詢的數據行(從0開始),參數2爲需要的行數。
查詢第10條到第20條的數據的sql是: select * from table limit 10,10;
->對應我們的需求就是查詢第二頁的數據:select * from table limit (2-1)*10,10;
-
Innodb每個數據頁的大小爲16KB,每個Page使用一個32位(一位表示的就是0或1)的int值來表示,正好對應Innodb最大64TB的存儲容量(16kb * 2^32=64tib)
-
redo log、undo log (1次)
MySQL日誌系統:redo log、binlog、undo log 區別與作用
常用數據結構
- 紅黑樹、紅黑樹的查找時間複雜度 (2次)
- 和高度平衡二叉樹 (1次)
- 哈希衝突解決辦法 (1次)
- 所有排序的時間複雜度、空間複雜度、最壞複雜度 (1次)
- 二叉排序樹,二叉平衡樹,樹的廣度優先遍歷 (1次)
- B+樹、B樹的插入刪除(1次)B樹和B+樹的插入、刪除圖文詳解
- 堆跟棧的區別 、堆的實現原理?(3次)
堆是完全二叉樹結構,完全二叉樹除了最底層,每一層都是滿的,最後一層節點集中在左側。最大堆:孩子節點要小於等於父親節點。最小堆:孩子節點要大於等於其父親節點。PriorityQueue 是基於二叉堆原理的優先隊列,隊列用動態數組實現。它是非阻塞的、非線程安全的;
堆的知識點:1、可用數組來存儲:其中某個節點爲,則其父節點爲,其左子節點爲,右子節點爲;2、(最大堆)插入堆:先插入到數組最後一個位置,然後不斷上浮,不斷跟其父節點比較,若比父節點大,則交換,若小於等於則停止操作。3、(最大堆)取出堆頂元素時:先去出數組第0個元素,再將數組最後一個元素複製到第0個位置上,刪除最後一個元素,將新的第0個元素下沉,即比較其左右子節點,哪個較大,並且比自己的值還大,則跟哪個子節點進行交換。4、數組堆化:找到最後一個非葉節點,即最後一個節點的父節點,即,然後開始逐個對非葉子節點進行下沉操作。
堆的實現原理
操作系統
- 線程和進程和協程的區別、既然線程會共享進程的程序和數據,那麼如何保證各個線程之間互不干擾相互獨立呢 ? 進程是操作系統資源分配的最小單位;線程爲輕量級進程,是操作系統調度(CPU調度)執行的最小單位;協程是一種用戶態的輕量級線程,一個線程可以擁有多個協程,協程調用完全由程序所控制,協程能保留上一次調用時的狀態,每次過程重入時,就相當於進入上一次調用的狀態(3次)
- 簡述一下什麼是死鎖,死鎖出現的原因、死鎖產生的必要條件。死鎖詳解 (2次)
死鎖的必要條件:(1)互斥條件:指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程佔用。如果此時還有其它進程請求資源,則請求者只能等待,直至佔有資源的進程用畢釋放。
(2)請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程佔有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。
(3)不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。
(4)環路等待條件:指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1佔用的資源;P1正在等待P2佔用的資源,……,Pn正在等待已被P0佔用的資源。 - 進程間通信的方式:
- 無名管道:半雙工的、只能用於具有親緣關係的進程之間的通信(也就是父子進程或者兄弟進程之間)、只存在於內存中的文件。
- 命名管道:遵循先進先出(first in first out)。命名管道以磁盤文件的方式存在,可以實現本機任意兩個進程通信。
- 消息隊列 :消息的鏈接表,存放在內核中,消息隊列可以實現消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取。
- 信號量 :信號量是一個計數器,用於多進程對共享數據的訪問,信號量的意圖在於進程間同步。這種通信方式主要用於解決與同步相關的問題並避免競爭條件。
- 共享內存: 使得多個進程可以訪問同一塊內存空間,不同進程可以及時看到對方進程中對共享內存中數據的更新。
- 套接字: 此方法主要用於在客戶端和服務器之間通過網絡進行通信。套接字是支持 TCP/IP 的網絡通信的基本操作單元,可以看做是不同主機之間的進程進行雙向通信的端點
進程間通信的方式(2次)
- 內存碎片 (1次)
- 線程安全 (1次)
- 操作系統大小端字節序 (1次)
- 進程調度算法 進程調度算法詳解(1次)
- 殭屍進程和孤兒進程? (1次)
殭屍進程:即子進程先於父進程退出後,子進程的PCB需要其父進程釋放,但是父進程並沒有釋放子進程的PCB(父進程是死循環)。
孤兒進程:一個父進程退出,而它的一個或多個子進程還在運行,那麼那些子進程將成爲孤兒進程。孤兒進程將被init進程(進程號爲1)所收養,並由init進程對它們完成狀態收集工作。所以孤兒進程實際上是不佔用資源的,因爲它終究是被系統回收了。不會像殭屍進程那樣佔用ID,損害運行系統。
Spring
- AOP實現原理 (3次)動態代理
- SpringMVC和Spring之間的關係? (3次)
- 動態代理實現原理 (1次)
- springboot中的註解?對於註解是怎麼理解的? (1次)
- Autowired底層原理?什麼時候做Autowired的注入?
在服務器啓動的時候,會加載配置文件,配置文件中有包掃描器和註解驅動,系統會根據配置進行掃描注入 bean。XML文件中<context:component-scan base-package=“com.zxt”/>
用來定義掃描的包;@Service用來聲明一個類是一個bean,該類在bean中的id是類名且首字母小寫。@Scope(“自定義名”)用來自定義bean的名稱。 - Autowired下邊有多個實現類,可不可以編譯?
不可以編譯,除非:1、變量名用userService1,userService2,而不是userService。通常情況下@Autowired是通過byType的方法注入的,可是在多個實現類的時候,byType的方式不再是唯一,而需要通過byName的方式來注入,而這個name默認就是根據變量名來的。2、通過@Qualifier註解來指明使用哪一個實現類,實際上也是通過byName的方式實現。@Autowired默認按照byType方式進行bean匹配,@Resource默認按照byName方式進行bean匹配(1次)
@Autowired、@Resource、@Inject和@Service介紹 - SpringMVC流程:
1、 用戶發送請求至前端控制器 DispatcherServlet。
2、 DispatcherServlet收到請求調用HandlerMapping處理器映射器。
3、 處理器映射器找到具體的處理器(可以根據xml配置、註解進行查找),生成處理器對象及處理器攔截器(如果有則生成)一併返回給DispatcherServlet。
4、 DispatcherServlet調用HandlerAdapter處理器適配器。
5、 HandlerAdapter經過適配調用具體的處理器(Controller,也叫後端控制器)。
6、 Controller執行完成返回ModelAndView。
7、 HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet。
8、 DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。
9、 ViewReslover解析後返回具體View。
10、DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中)。
11、 DispatcherServlet響應用戶。 - Spring 中的 IoC 的實現原理? (1次)工廠模式加反射機制。
- Bean的生命週期? (1次)
- Spring對bean進行實例化
- Spring爲bean的屬性設置值和對其他bean的引用
- 如果bean實現了BeanNameAware接口,Spring將bean的ID傳遞給setBean-Name()方法;
- 如果bean實現了BeanFactoryAware接口,Spring將調用setBeanFactory()方法,將BeanFactory容器實例傳入;
- 如果bean實現了ApplicationContextAware接口,Spring將調用setApplicationContext()方法,將bean所在的應用上下文的引用傳入進來;
- 如果bean實現了BeanPostProcessor接口,Spring將調用它們的postProcessBeforeInitialization()方法;
- bean初始化
- 如果bean實現了BeanPostProcessor接口,Spring將調用它們的post-ProcessAfterInitialization()方法;
- 此時,bean已經準備就緒,可以被應用程序使用了,它們將一直駐留在應用上下文中,直到該應用上下文被銷燬;
- 銷燬bean,如果bean實現了DisposableBean接口,Spring將調用它的destroy()接口方法。
- Spring Ioc容器初始化過程? (1次)
1、Resource 定位。我們一般用外部資源來描述 Bean 對象,所以在初始化 IOC 容器的第一步就是需要定位這個外部資源。
2、BeanDefinition 的載入和解析。裝載就是 BeanDefinition 的載入。BeanDefinitionReader 讀取、解析 Resource 資源,也就是將用戶定義的 Bean 表示成 IOC 容器的內部數據結構:BeanDefinition。
3、BeanDefinition 註冊。將BeanDefinition 注入到一個 HashMap 容器中,IOC 容器就是通過這個 HashMap 來維護這些 BeanDefinition 的,key爲BeanName,value爲BeanDefinition。在這裏需要注意的一點是這個過程並沒有完成依賴注入,依賴註冊是發生在應用第一次調用 getBean() 向容器索要 Bean 時。當然我們可以通過設置預處理,即對某個 Bean 設置 lazyinit 屬性,那麼這個 Bean 的依賴注入就會在容器初始化的時候完成。
Spring 之 IOC 初始化總結
設計模式
- 單例模式: 確保一個類只有一個實例,並提供該實例的全局訪問點。可以直接訪問,不需要實例化該類的對象。解決:一個全局使用的類頻繁地創建與銷燬。使用場景:1、要求生產唯一序列號。2、WEB 中的計數器,不用每次刷新都在數據庫里加一次,用單例先緩存起來。3、創建的一個對象需要消耗的資源過多,比如 I/O 與數據庫的連接等。
- 懶漢式,線程不安全:如果多個線程能夠同時進入
if (uniqueInstance == null)
,並且此時 instance 爲 null,那麼會有多個線程執行instance = new Singleton();
語句,這將導致實例化多次 instance。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 懶漢式,線程安全:只需要對 getInstance() 方法加鎖,那麼在一個時間點只能有一個線程能夠進入該方法,從而避免了實例化多次 instance。優點:第一次調用才初始化,避免內存浪費。缺點:必須加鎖 synchronized 才能保證單例,但加鎖會影響效率。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 餓漢式,線程安全: 優點: 沒有加鎖,執行效率會提高。缺點: 類加載時就初始化,浪費內存。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
- 雙重校驗鎖,線程安全: 這種方式採用雙鎖機制,安全且在多線程情況下能保持高性能。雙重校驗鎖先判斷 instance 是否已經被實例化,如果沒有被實例化,那麼纔對實例化語句進行加鎖。
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
- 靜態內部類,線程安全: 當 Singleton 類被加載時,靜態內部類 SingletonHolder 沒有被加載進內存。只有當調用 getInstance() 方法從而觸發 SingletonHolder.INSTANCE 時 SingletonHolder 纔會被加載,此時初始化 INSTANCE 實例,並且 JVM 能確保 INSTANCE 只被實例化一次。這種方式不僅具有延遲初始化的好處,而且由 JVM 提供了對線程安全的支持。
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
- 枚舉,線程安全:
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
參考:單例模式|菜鳥教程
- 工廠模式:
public interface People {
public void eat();
public void run();
public class Xiaoming implements People{
@Override
public void eat() {
System.out.println("小明喫飯");
}
@Override
public void run() {
System.out.println("小明跑步");
}
}
public class Xiaohong implements People{
@Override
public void eat() {
System.out.println("小紅喫飯");
}
@Override
public void run() {
System.out.println("小紅跑步");
}
}
public class PeopleFactory {
public People getPeople(String name){
if(name.equals("Xiaoming")){
return new Xiaoming();
}else if(name.equals("Xiaohong")){
return new Xiaohong();
}
return null;
}
}
public class Main {
public void testSign(){
PeopleFactory peopleFactory = new PeopleFactory();
People people = peopleFactory.getPeople("Xiaohong");
}
}
- 策略模式與工廠模式的區別? (1次)
- 工廠是創建型模式,它的作用就是創建對象;策略是行爲型模式,它的作用是讓一個對象在許多行爲中選擇一種行爲。
- 工廠模式關注對象創建,策略模式關注行爲的封裝。
- 工廠模式中只管生產實例,具體怎麼使用工廠實例由調用方決定,策略模式是將生成實例的使用策略放在策略類中配置後才提供調用方使用。 工廠模式調用方可以直接調用工廠實例的方法屬性等,策略模式不能直接調用實例的方法屬性,需要在策略類中封裝策略後調用。
個人理解簡單工廠模式和策略模式的區別
Java設計模式之策略模式+工廠模式(反射和註解)
Redis
- 怎麼用redis?都在什麼場景下用了?Redis存儲的基本數據類型、底層數據結構(3次)常用數據結構:String、List、Hash、Set、SortedSet、HyperLogLog、位圖、地理信息定位
- 刪除策略 (1次)
- redis持久化? (1次)
- 詳細講一下aof怎麼做記錄備份?aof和rdb的使用場景(1次)
- 介紹一下redis的過期策略? (1次)
- redis的單線程模型機制(1次)
- 講講redis sorted set (有序的set) (1次)
- 跳錶? (1次)
Mybatis
- Mybatis一級緩存和二級緩存 (1次)
- Mybatis的String結構如何實現的(int、embstr、row (sds動態內存)) (1次)
- Mybatis的Set如何實現(zlist、hashtable),一個key可以存儲的最大數量 (1次)
- Mybatis工作原理 (1次)
- 什麼是MyBits三劍客? (1次)
RocketMq
- 用來解決什麼問題(流量削峯) (1次)
- 如何保證通信(底層使用的是Netty通信框架,Netty包裝的NIO)(1次)
- 爲什麼使用Channel(NIO相關)(1次)
- 線程池+RocketMQ+設計模式 (1次)
場景題
- 32位的機器 文件裏每行有一個整型數字 找出不重複的個數(之前沒看過bitmap,說了hashmap分析了一下時間空間複雜度,面試官引導我最後也只說到了bitmap沒說出來怎麼實現) (1次)
- 一個數量爲1000的線程池,如何使用固定的線程去實現特定的任務。 (1次)
- 自己實現RPC怎麼做。 反射+代理+序列化+socket (1次)
- 註冊+審覈流程 多線程審覈,如何實現併發控制? (1次)
- 如何在很多的用戶ID中找出登錄次數最多的那個用戶。 (1次)
- 如何設計一個微博熱搜? (1次)
- 掃碼登錄如何實現,微信支付怎麼實現 (1次)
- kmp算法 (1次)
- 如果讓你實現一個用戶在另一臺手機上登錄微信後把他之前登錄的那臺手機上微信號頂掉你該怎麼設計? (1次)
- 如果讓你來實現一個對高考成績的分類下的前100名成績你該怎麼實現?說說你的思路(我也不知道對不對 我答的是使用hash函數將不同科目的成績分配到不同的文件然後在使用堆排序或者快排求解topk問題)
- 假設你這個博客項目要應對高併發的場景,你從那些方面進行優化?
(頁面靜態化、CDN加速、Nginx負載均衡、服務器集羣、MySQL分區、集羣、讀寫分離、Redis緩存、mq削峯限流…) (1次) - 網頁訪問人數設計 (1次)
- 海量場景題
手撕代碼
- 字符串A去掉字符串B出現字符 (1次)
- 二叉樹從根到葉節點是否等於一個值 (1次)
- 一個二維數組,橫向遞增,縱向遞增,求解是否某個數存在 (1次)
- 給出N,求1~N中每一位數乘起來乘積最大,比如220最大的就是199,288最大的是288 (1次)
- topK問題 (1次)
- 設計一個論壇的數據庫表,從範式,索引角度思考,要考慮到大量的讀寫需求,寫完給面試官講。 (1次)
- 寫一個死鎖。 (1次)
package com.jianzhi;
public class DeadLock {
Object a = new Object();
Object b = new Object();
public static void main(String[] args) {
DeadLock lock=new DeadLock();
lock.deadLock();
}
public void deadLock(){
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
synchronized (a){
System.out.println("我有筆,沒有本");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b){
System.out.println("我有筆,也有本");
}
}
}
});
Thread thread1=new Thread(new Runnable() {
@Override
public void run() {
synchronized (b){
System.out.println("我有本,沒有筆");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a){
System.out.println("我有本,也有筆");
}
}
}
});
thread1.start();
thread.start();
}
}
- 寫一個OOM (1次)
public static void main(String[] args) {
ArrayList<int[]> list = new ArrayList<>();
while (true) {
list.add(new int[2000000000]);
}
}
- 用Java實現LRU。 (1次)
用帶有頭節點和尾節點的雙向鏈表和Hashmap實現,HashMap裏存放的是<K k, Node node>
import java.util.HashMap;
import java.util.Iterator;
public class LRU<K> implements Iterable<K> {
private Node head;
private Node tail;
private HashMap<K, Node> map;
private int maxSize;
private class Node {
Node pre;
Node next;
K k;
public Node(K k) {
this.k = k;
}
}
public LRU(int maxSize) {
this.maxSize = maxSize;
this.map = new HashMap<>(maxSize * 4 / 3);
head = new Node(null);
tail = new Node(null);
head.next = tail;
tail.pre = head;
}
public K get(K key) {
if (!map.containsKey(key)) {
return null;
}
Node node = map.get(key);
unlink(node);
appendHead(node);
return node.k;
}
public void put(K key) {
if (map.containsKey(key)) {
Node node = map.get(key);
unlink(node);
}
Node node = new Node(key);
map.put(key, node);
appendHead(node);
if (map.size() > maxSize) {
Node toRemove = removeTail();
map.remove(toRemove.k);
}
}
private void unlink(Node node) {
Node pre = node.pre;
Node next = node.next;
pre.next = next;
next.pre = pre;
node.pre = null;
node.next = null;
}
private void appendHead(Node node) {
Node next = head.next;
node.next = next;
next.pre = node;
node.pre = head;
head.next = node;
}
private Node removeTail() {
Node node = tail.pre;
Node pre = node.pre;
tail.pre = pre;
pre.next = tail;
node.pre = null;
node.next = null;
return node;
}
@Override
public Iterator<K> iterator() {
return new Iterator<K>() {
private Node cur = head.next;
@Override
public boolean hasNext() {
return cur != tail;
}
@Override
public K next() {
Node node = cur;
cur = cur.next;
return node.k;
}
};
}
public static void main(String[] args) {
LRU<String> lru = new LRU<>(3);
lru.put("one");
lru.put("two");
lru.put("three");
lru.put("two");
lru.put("four");
}
}
-
最長公共子串與最長公共子序列 (1次) 最長公共子串與最長公共子序列
-
撕一個線程安全的單例懶漢模式 (1次)
-
層次遍歷二叉樹 (1次)
-
鏈表是否相交 (1次)
-
某字符串的所有排列組合。 (1次)
-
兩個線程交替執行,一個輸出偶數,一個輸出奇數 (1次)
方法一
Linux
- 內存的使用情況如何實現定時任務? (1次)
- ps -ef | grep -i redis
Tomcat
- Tomcat怎麼切換IO模型? (1次)
- Tomcat啓動模型? (1次)
其他技能相關
- docker底層原理 (1次)
- maven熟嗎,如果遇到版本不匹配的問題怎麼解決? (1次)
- Hadoop,MapReduce,HDFS (1次)
- 什麼是跨域問題?(1次)