一面
1、聊聊你研究生的課題(智能機器人相關)
2、幾個人做的啊,分工是什么樣的
3、如果以后想把你們做的東西商業化 產品化,怎么去收集用戶的資訊?
云?用戶定期上傳資料到云服務器,公司負責處理這些資料(不懂,朝著云的方向扯了一些)
4、 行程與執行緒的區別
調度:行程是資源管理分配的基本單位,執行緒是程式執行調度的基本單位,
切換:執行緒背景關系切換比行程背景關系切換要快得多,
擁有資源: 行程是擁有資源的一個獨立單位,執行緒不擁有系統資源,但是可以訪問隸屬于行程的資源,
系統開銷: 創建或撤銷行程時,系統都要為之分配或回收系統資源,如記憶體空間,I/O設備等,OS所付出的開銷顯著大于在創建或撤銷執行緒時的開銷,行程切換的開銷也遠大于執行緒切換的開銷,
5、執行緒一般存在什么地方?執行緒里有什么東西?
額,有沒有大佬懂的評論區指導一波,當時卡住了,,
6、說說看自己對LRU的理解,實作思路
最近最少使用機制,是作業系統中用來實作頁面替換的一種優秀的演算法,本質上是一種雙向鏈表的資料結構,用哈希表來輔助維護里面的節點位置,插入時先看看哈希表里有鍵值沖突:沒有的話,用鍵值新構造一個節點,插入到鏈表中,并移到鏈表頭,再看看有沒有越界,越了的話要把尾部節點洗掉;同時放入哈希表中,有的話,用新值代替舊值,然后移到鏈表頭,若讀取,判斷鍵對應的節點存不存在,存在的話讀值并把節點移到頭部,其中涉及到把節點移到鏈表頭、洗掉鏈表尾的操作,附上實作,面試官讓口述:
public class Solution {
/**
* lru design
* @param operators int整型二維陣列 the ops
* @param k int整型 the k
* @return int整型一維陣列
*/
class DoubleListNode {
int key;
int val;
DoubleListNode pre;
DoubleListNode next;
DoubleListNode() {}
DoubleListNode(int key, int val) {
this.key = key;
this.val = val;
}
}
DoubleListNode head = new DoubleListNode(-1, -1);
DoubleListNode tail = new DoubleListNode(-1, -1);
HashMap<Integer, DoubleListNode> map = new HashMap<>();
public int[] LRU (int[][] operators, int k) {
// write code here
ArrayList<Integer> ans = new ArrayList<>();
head.next = tail;
tail.pre = head;
int size = 0;
for(int i = 0; i < operators.length; i++){
int tmp_key = operators[i][1];
DoubleListNode node = map.get(tmp_key);
if(operators[i][0] == 1){
if(node == null){
DoubleListNode new_node = new DoubleListNode(tmp_key, operators[i][2]);
map.put(tmp_key, new_node);
add2head(new_node);
size++;
if(size > k){
DoubleListNode weiba = removeTail();
map.remove(weiba.key);
size--;
}
}else{
node.val = operators[i][2];
add2head(node);
}
}else{
// node = map.get(tmp_key);
if(node == null) ans.add(-1);
else{
ans.add(node.val);
move2head(node);
}
}
}
int[] res = new int[ans.size()];
for(int i = 0; i < ans.size(); i++){
res[i] = ans.get(i);
}
return res;
}
void move2head(DoubleListNode node){
removeNode(node);
add2head(node);
}
void removeNode(DoubleListNode node){
node.pre.next = node.next;
node.next.pre = node.pre;
}
void add2head(DoubleListNode node){
node.pre = head;
node.next = head.next;
head.next.pre = node;
head.next = node;
}
DoubleListNode removeTail(){
DoubleListNode weiba = tail.pre;
removeNode(tail.pre);
return weiba;
}
}
7、你是怎么理解執行緒安全的,為什么會出現執行緒安全的問題呢
執行緒安全就是說多執行緒訪問同一段代碼,不會產生不確定的結果 ,
理解執行緒安全的兩個方面:執行控制和記憶體可見,
執行控制的目的是控制代碼執行(順序)及是否可以并發執行,
記憶體可見控制的是執行緒執行結果在記憶體中對其它執行緒的可見性,根據Java記憶體模型的實作,執行緒在具體執行時,會先拷貝主存資料到執行緒本地(CPU快取),操作完成后再把結果從執行緒本地刷到主存,
具體的就是去保證原子性、有序性和可見性,
為什么,我當時回答的是多執行緒操作共享資源時無法保證原子性、有序性和可見性,面試官讓結束后再思考一下,請教大佬們指點,
8、怎么解決,有哪些方法
加鎖,volatile,原子類,并發包里的一堆東西,按需所求,
9、同步鎖有什么問題啊,jdk對此做了啥改進
java的執行緒是映射到作業系統原生執行緒之上的,如果要阻塞或喚醒一個執行緒就需要作業系統介入,需要在用戶態與內核態之間切換,這種切換會消耗大量的系統資源,因為用戶態與內核態都有各自專用的記憶體空間、專用的暫存器等,用戶態切換至內核態需要傳遞給許多變數、引數給內核,內核也需要保護好用戶態在切換時的一些暫存器值和變數等,以便內核態呼叫結束后切換回用戶態繼續作業,
如果執行緒狀態切換是一個高頻操作時,會消耗很多CPU處理時間;對于那些需要同步的簡單代碼塊,獲取鎖、阻塞掛起操作消耗的時間比用戶代碼執行的時間還要長,這種同步策略顯然得不償失的,
synchronized會導致競爭不到鎖的執行緒進入阻塞狀態,所以說它是java語言中一個重量級的同步操縱,被稱為重量級鎖,為了緩解上述性能問題,引入了輕量鎖與偏向鎖,默認啟用了自旋鎖,他們都屬于樂觀鎖,
鎖升級:最開始的時候處于一個無鎖的狀態,加鎖時首先是偏向鎖,當前獲取到鎖資源的執行緒,會優先讓它再去獲取這個鎖,如果他沒有獲取到這個鎖,就會升級到一個輕量級鎖,比如用CAS來嘗試獲取鎖,如果沒有獲取成功就自旋,如果自旋了一定次數后,就會升級到synchronized這個重量級鎖,保證了性能,
10、自旋鎖會消耗cpu嗎,為啥
執行緒自旋是需要消耗cpu的,說白了就是讓cpu在做無用功,如果一直獲取不到鎖,那執行緒也不能一直占用cpu自旋做無用功,所以需要設定一個自旋等待的最大時間,
反問:攜程主要有哪些業務,對我做個簡短的評價
一面小結:感覺這個面試官是秋招第一次面試,一開始就說:你等幾分鐘,我研究一下你的簡歷hhh,后面問問題的時候每問一個問題都要等個幾十秒,嘴上還咕噥著:我想想問個什么好呢,哈哈哈太可愛了,整體上回答的還可以,問的不深,
二面
1、手寫一個堆排序
上來就來這有點難頂,寫了二十多分中,,,一開始想用PrioityQueue偷懶的被面試官制止了(hh他笑著說:你住手),要求自己用陣列模擬堆來寫,真不容易,還好不久前看過(背過),
class Solution {
public int[] sortArray(int[] nums) {
heapSort(nums);
return nums;
}
public void heapSort(int[] nums) {
int len = nums.length - 1;
buildMaxHeap(nums, len);
for (int i = len; i >= 1; --i) {
swap(nums, i, 0);
len -= 1;
maxHeapify(nums, 0, len);
}
}
public void buildMaxHeap(int[] nums, int len) {//構建堆
for (int i = len / 2; i >= 0; --i) {
maxHeapify(nums, i, len);
}
}
public void maxHeapify(int[] nums, int i, int len) {
for (; (i << 1) + 1 <= len;) {
int lson = (i << 1) + 1;
int rson = (i << 1) + 2;
int large;
if (lson <= len && nums[lson] > nums[i]) {
large = lson;
} else {
large = i;
}
if (rson <= len && nums[rson] > nums[large]) {
large = rson;
}
if (large != i) {
swap(nums, i, large);
i = large;
} else {
break;
}
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
2、問商城專案
簡歷寫了一個看視頻跟著做的商城網站,沒啥好問的,面試官問了一些開放題:怎么避免庫存超賣,redis可以用在什么地方,有什么作用,怎么保證用戶資訊的安全等等;
需要這個商城網站專案原始碼的朋友可以關注微信公眾號:Java團長,然后發送“商城”即可獲取~
3、對threadLocal的理解、底層原理
ThreadLocal是 JDK java.lang 包下的一個類,ThreadLocal為變數在每個執行緒中都創建了一個副本,那么每個執行緒可以訪問自己內部的副本變數,并且不會和其他執行緒的區域變數沖突,實作了執行緒間的資料隔離,ThreadLocal的應用場景主要有:
(1)保存執行緒背景關系資訊,在需要的地方可以獲取
(2)執行緒間資料隔離
(3)資料庫連接;
底層原理:每個執行緒的內部都維護了一個 ThreadLocalMap,它是一個鍵值對資料格式,key 是一個弱參考,也就是 ThreadLocal 本身,而 value 是強參考,存的是執行緒變數的值,也就是說 ThreadLocal 本身并不存盤執行緒的變數值,它只是一個工具,用來維護執行緒內部的 Map,幫助存和取變數,
4、使用threadLocal會出現什么問題
ThreadLocal 在 ThreadLocalMap 中是以一個弱參考身份被 Entry 中的 Key 參考的,因此如果 ThreadLocal 沒有外部強參考來參考它,那么 ThreadLocal 會在下次 JVM 垃圾收集時被回收,這個時候 Entry 中的 key 已經被回收,但是 value 又是一強參考不會被垃圾收集器回收,這樣 ThreadLocal 的執行緒如果一直持續運行,value 就一直得不到回收,這樣就會發生記憶體泄露,
5、ThreadLocal的key是哪種參考型別?為啥這么設計?
ThreadLocalMap 中的 key 是弱參考,而 value 是強參考才會導致記憶體泄露的問題
- 若key 使用強參考:這樣會導致一個問題,參考的 ThreadLocal 的物件被回收了,但是 ThreadLocalMap 還持有 ThreadLocal 的強參考毫無意義,如果沒有手動洗掉,ThreadLocal 不會被回收,則會導致記憶體泄漏,
- 若key 使用弱參考:這樣的話,參考的 ThreadLocal 的物件被回收了,由于 ThreadLocalMap 持有 ThreadLocal 的弱參考,即使沒有手動洗掉,ThreadLocal 也會被回收,value 在下一次 ThreadLocalMap 呼叫 set、get、remove 的時候會被清除(清理key為null的記錄),使用完了ThreadLocal最好在手動的remove一下,
- 比較以上兩種情況:由于 ThreadLocalMap 的生命周期跟 Thread 一樣長,如果都沒有手動洗掉對應 key,都會導致記憶體泄漏,但是使用弱參考可以多一層保障,弱參考 ThreadLocal 不會記憶體泄漏,對應的 value 在下一次 ThreadLocalMap 呼叫 set、get、remove 的時候被清除,算是最優的解決方案,
6、什么是記憶體泄漏
記憶體泄漏是指用戶向系統申請分配記憶體進行使用,可是使用完了以后卻沒有釋放,結果那塊記憶體用戶不能訪問(也許你把它的地址給弄丟了),而系統也不能再把它分配給需要的程式,
7、Java有哪些參考型別?分別有哪些使用場景
- 強參考,任何時候都不會被;垃圾回收器回收,如果記憶體不足,寧愿拋出OutOfMemoryError
使用場景:我們平常大部分使用的場景都是使用了強參考,比如new創建物件,反射獲得一個物件等, - 軟參考,只有在記憶體將滿的時候才會被垃圾回收器回收,如果還有可用記憶體,垃圾回收器不會回收,
軟參考可以和一個參考佇列進行關聯,如果這個軟參考的物件被垃圾回收,就會將這個軟參考加入到關聯的佇列中去, 可用于高速快取, - 弱參考(WeakReference),生命周期更短,只要垃圾回收器運行,就肯定會被回收,不管還有沒有可用記憶體,
使用場景: 弱參考用于生命周期更短的,對記憶體更敏感的場景中,比如占用記憶體很大的Map,java api中就提供了WeakHashMap使用,就會是的大Map被及時清理掉, - 虛參考(PhantomReference),虛參考等于沒有參考,任何時候都有可能被垃圾回收,虛參考必須和參考佇列聯合使用,參考佇列的作用和軟弱參考一樣,
使用場景: 我覺得他的使用場景應該在判斷一個物件是否被垃圾回收了,什么時候參考佇列有新的參考入隊了,就說明他被回收了,
反問:部門業務(火車票、機票),技術堆疊介紹
二面小結:二面主要考察的還是演算法與基礎知識,不過問的沒那么廣了,主要對ThreadLocal相關的技術原理展開,自己答的一般,平時確實沒用過這個東西,只能硬著頭皮去討論,不過面試官似乎很有耐心,先等我寫了好久的代碼,然后還給我解釋自己不會的地方,很nice
攜程一二面的面試題難度跟位元組跳動的比起來感徑訓是有很大差距的!!!
10月份位元組跳動Java面經匯總(資訊量有點大):https://docs.qq.com/doc/DTVRQU3BCQ3ZTanZK
HR面
- 自我介紹
- 專案介紹
- 未來對專案的更新迭代有哪些打算
- 跟小伙伴合作的時候出現過分歧嗎?怎么解決
- 老家在哪,家庭成員
- 哪位家人對自己影響最大,為什么
- 為什么想來上海,攜程對你吸引最大的點在哪里
- 手里有其他公司的offer嗎
- 你對之前的兩位面試官印象如何,簡單評價一下(我來評價面試官?)
- 想不想知道他們對你的評價?(hh好可愛的hr)
- 反問:未來部門分配,導師制度等
總結:攜程整個流程非常順利,基本上筆試以及每一輪的面試之間都是個了一周左右,面試官看起來都像是35左右的大哥,對候選人很友好,至少態度還是很禮貌的,能感覺到對方還是有一些期待的!問的問題還算常規,一面廣度,二面深度,HR面綜合,(HR的聲音太好聽了,我說什么她都回答:好呀)
面試中遇到的問題(沒回答好的問題)
- 關于執行緒內部有哪些東西,執行緒的本質以及它和jvm之間的關系
- redis在交易類系統中一般會有哪些應用,當時只回答了把熱點資料存redis,應該還有很多其他的應用
最后,點個贊吧,別光收藏,哈哈哈~
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/353381.html
標籤:java
