今天騰訊內(nèi)網(wǎng)在熱火朝天地集體算賬
共 8079字,需瀏覽 17分鐘
·
2024-07-12 14:04
大家好,我是二哥呀。
在星球嘉賓 Jack 那里看到一條消息說,鵝廠內(nèi)網(wǎng)正在熱火朝天的集體算賬:一是把年終獎的一部分提前攤?cè)氲?base 中,二是把房補也平均納入到 base 當中。
這個薪酬調(diào)整說實話對于 base 低的小伙伴來說很有利,因為 base 高了意味著五險一金繳納的更多了,每個月到手的也更多了,真正的落袋為安。
話說這公積金如果離職的話,也是可以提取的,相當于一筆不小的存款。當然了,騰訊的工作體感在所有的大廠里算是很友好的了,估計進了就不想走,除非(??)。
但對于 base 已經(jīng)非常高的小伙伴來說,每個月的個人所得稅交的就更多了,但我想既然掙的多,多納點稅也算是合情合理(反正我每個月也交不少)。
至于騰訊為什么做出這個調(diào)整,我想肯定是奔著為員工謀福利去的。說實話,這年頭,肯為員工謀福利的好公司不多了,騰訊這波值得被點贊。星球里之前也有好幾個球友拿到了騰訊的實習 offer,希望都穩(wěn)穩(wěn)轉(zhuǎn)個正。
那今天我們就以《Java 面試指南》中收錄的《騰訊面經(jīng)同學 26 微信支付暑期實習》 面試為例,來看看騰訊的面試官都喜歡問哪些問題,好做到知彼知己百戰(zhàn)不殆。
這次面試的整體難度感覺不大,三道算法題也是 LeetCode 上 100 題中筆刷的題目,八股的話也都是非常常見的,屬于送分八股(??)。
1、二哥的 Linux 速查備忘手冊.pdf 下載 2、三分惡面渣逆襲在線版:https://javabetter.cn/sidebar/sanfene/nixi.html
騰訊微信支付面經(jīng)
說一說項目的亮點。
PmHub 是一套基于 SpringCloud Alibaba & LLM 的智能項目管理系統(tǒng),目前拆分了用戶、流程、項目管理、認證等 4 個微服務,這個項目的亮點很多,比如說:
-
Gateway 實現(xiàn)自定義網(wǎng)關(guān)統(tǒng)一鑒權(quán)統(tǒng)計接口調(diào)用時間 -
使用 Redis+Lua 基于令牌桶實現(xiàn)限流 -
使用 RocketMQ 實現(xiàn)審批消息異步解耦 -
集成 OpenFeign+Sentinel 實現(xiàn)服務降級和網(wǎng)關(guān)流量控制 -
集成 Redis 分布式鎖保障流程狀態(tài)更新 -
通過分布式事務 Seata 保證任務審批狀態(tài)一致性 -
自定義注解+AOP 實現(xiàn)服務接口鑒權(quán)和內(nèi)部認證 -
整合 TTL 緩存用戶數(shù)據(jù) -
如何用 Docker 容器化部署項目 -
使用 Skywalking 監(jiān)控項目性能 -
采用 Cache Aside 模式保證緩存和數(shù)據(jù)庫一致性
JVM垃圾刪除
垃圾回收(Garbage Collection,GC),顧名思義就是釋放垃圾占用的空間,防止內(nèi)存爆掉。有效的使用可以使用的內(nèi)存,對內(nèi)存堆中已經(jīng)死亡的或者長時間沒有使用的對象進行清除和回收。
JVM 在做垃圾回收之前,需要先搞清楚什么是垃圾,什么不是垃圾,那么就需要一種垃圾判斷算法,通常有引用計數(shù)算法、可達性分析算法。
在確定了哪些垃圾可以被回收后,垃圾收集器要做的事情就是進行垃圾回收,如何高效地進行垃圾回收呢?
可以采用標記清除算法、復制算法、標記整理算法、分代收集算法等。
JVM 提供了多種垃圾回收器,包括 CMS GC、G1 GC、ZGC 等,不同的垃圾回收器采用的垃圾收集算法也不同,因此適用于不同的場景和需求。
CMS 是第一個關(guān)注 GC 停頓時間(STW 的時間)的垃圾收集器,JDK 1.5 時引入,JDK9 被標記棄用,JDK14 被移除。
G1(Garbage-First Garbage Collector)在 JDK 1.7 時引入,在 JDK 9 時取代 CMS 成為了默認的垃圾收集器。
ZGC 是 JDK11 推出的一款低延遲垃圾收集器,適用于大內(nèi)存低延遲服務的內(nèi)存管理和回收,在 128G 的大堆下,最大停頓時間才 1.68 ms,性能遠勝于 G1 和 CMS。
https的加密技術(shù)
使用 HTTPS 主要是為了解決 HTTP 傳輸過程中的一些安全問題,因為 HTTP 是明文傳輸,所以 HTTPS 在 HTTP 的基礎(chǔ)上加入了 SSL/TLS 協(xié)議。
SSL(安全套接字)/TLS(傳輸層安全)協(xié)議可以用來加密通信內(nèi)容,保證通信過程中的數(shù)據(jù)不被竊取和篡改。整個加密過程主要涉及兩種類型的加密方法:
-
非對稱加密:服務器向客戶端發(fā)送公鑰,然后客戶端用公鑰加密自己的隨機密鑰,也就是會話密鑰,發(fā)送給服務器,服務器用私鑰解密,得到會話密鑰。 -
然后雙方用會話密鑰加密通信內(nèi)容。
客戶端會通過數(shù)字證書來驗證服務器的身份,數(shù)字證書由 CA(證書權(quán)威機構(gòu))簽發(fā),包含了服務器的公鑰、證書的頒發(fā)機構(gòu)、證書的有效期等信息。
說一說常用的并發(fā)容器
我自己常用的并發(fā)容器主要有 ConcurrentHashMap、CopyOnWriteArrayList、LinkedBlockingQueue。
在 JDK 8 及以上版本中,ConcurrentHashMap 的實現(xiàn)進行了優(yōu)化,不再使用分段鎖,而是使用了一種更加精細化的鎖——桶鎖,以及 CAS 無鎖算法。每個桶(Node 數(shù)組的每個元素)都可以獨立地加鎖,從而實現(xiàn)更高級別的并發(fā)訪問。
同時,對于讀操作,通常不需要加鎖,可以直接讀取,因為 ConcurrentHashMap 內(nèi)部使用了 volatile 變量來保證內(nèi)存可見性。
對于寫操作,ConcurrentHashMap 使用 CAS 操作來實現(xiàn)無鎖的更新,這是一種樂觀鎖的實現(xiàn),因為它假設沒有沖突發(fā)生,在實際更新數(shù)據(jù)時才檢查是否有其他線程在嘗試修改數(shù)據(jù),如果有,采用悲觀的鎖策略,如 synchronized 代碼塊來保證數(shù)據(jù)的一致性。
CopyOnWriteArrayList 是一個線程安全的 ArrayList,它遵循寫時復制(Copy-On-Write)的原則,即在寫操作時,會先復制一個新的數(shù)組,然后在新的數(shù)組上進行寫操作,寫完之后再將原數(shù)組引用指向新數(shù)組。
這樣,讀操作總是在一個不變的數(shù)組版本上進行的,就不需要同步了。
ArrayBlockingQueue 是一個基于數(shù)組的有界阻塞隊列,采用 ReentrantLock 鎖來實現(xiàn)線程的互斥,而 ReentrantLock 底層采用的是 AQS 實現(xiàn)的隊列同步,線程的阻塞調(diào)用 LockSupport.park 實現(xiàn),喚醒調(diào)用 LockSupport.unpark 實現(xiàn)。
算法題
LRU
這道題先不按照 leetcode 的解法來寫,直接告訴大家我們可以使用 LinkedHashMap 來實現(xiàn) LRU 緩存,LRU 是 Least Recently Used 的縮寫,即最近最少使用,是一種常用的頁面置換算法,選擇最近最久未使用的頁面予以淘汰。
public class MyLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
private static final int MAX_ENTRIES = 5; // 表示 MyLinkedHashMap 中最多存儲的鍵值對數(shù)量
public MyLinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor, accessOrder);
}
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
}
MyLinkedHashMap 是一個自定義類,它繼承了 LinkedHashMap,并且重寫了 removeEldestEntry() 方法——使 Map 最多可容納 5 個元素,超出后就淘汰。
我們來測試一下。
MyLinkedHashMap<String,String> map = new MyLinkedHashMap<>(16,0.75f,true);
map.put("沉", "沉默王二");
map.put("默", "沉默王二");
map.put("王", "沉默王二");
map.put("二", "沉默王二");
map.put("一枚有趣的程序員", "一枚有趣的程序員");
System.out.println(map);
map.put("一枚有顏值的程序員", "一枚有顏值的程序員");
System.out.println(map);
map.put("一枚有才華的程序員","一枚有才華的程序員");
System.out.println(map);
輸出結(jié)果如下所示:
{沉=沉默王二, 默=沉默王二, 王=沉默王二, 二=沉默王二, 一枚有趣的程序員=一枚有趣的程序員}
{默=沉默王二, 王=沉默王二, 二=沉默王二, 一枚有趣的程序員=一枚有趣的程序員, 一枚有顏值的程序員=一枚有顏值的程序員}
{王=沉默王二, 二=沉默王二, 一枚有趣的程序員=一枚有趣的程序員, 一枚有顏值的程序員=一枚有顏值的程序員, 一枚有才華的程序員=一枚有才華的程序員}
沉=沉默王二 和 默=沉默王二 依次被淘汰出局。
接雨水
這道題我在《二哥的 LeetCode 刷題筆記》中給出詳細的題解,這里就先貼個圖作證。
刪除鏈表中倒數(shù)第n個節(jié)點。
這是 LeetCode 的第 19 題,我這里直接給出題解,也是直接能 beat 100% 的:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
// 創(chuàng)建一個虛擬頭節(jié)點,簡化邊界條件處理
ListNode dummy = new ListNode(0);
dummy.next = head;
// 第一次遍歷,計算鏈表的總長度
int length = 0;
ListNode current = head;
while (current != null) {
length++;
current = current.next;
}
// 設置長度為到達要刪除的節(jié)點的前一個節(jié)點
int index = length - n;
current = dummy;
// 第二次遍歷,找到要刪除的節(jié)點的前一個節(jié)點
for (int i = 0; i < index; i++) {
current = current.next;
}
// 刪除節(jié)點,即跳過要刪除的節(jié)點
current.next = current.next.next;
return dummy.next;
}
}
內(nèi)容來源
-
星球嘉賓三分惡的面渣逆襲:https://javabetter.cn/sidebar/sanfene/nixi.html -
二哥的 Java 進階之路(GitHub 已有 12000+star):https://javabetter.cn
ending
一個人可以走得很快,但一群人才能走得更遠。二哥的編程星球已經(jīng)有 5700 多名球友加入了,如果你也需要一個良好的學習環(huán)境,戳鏈接 ?? 加入我們吧。這是一個編程學習指南 + Java 項目實戰(zhàn) + LeetCode 刷題的私密圈子,你可以閱讀星球?qū)?、向二哥提問、幫你制定學習計劃、和球友一起打卡成長。
兩個置頂帖「球友必看」和「知識圖譜」里已經(jīng)沉淀了非常多優(yōu)質(zhì)的學習資源,相信能幫助你走的更快、更穩(wěn)、更遠。
歡迎點擊左下角閱讀原文了解二哥的編程星球,這可能是你學習求職路上最有含金量的一次點擊。
最后,把二哥的座右銘送給大家:沒有什么使我停留——除了目的,縱然岸旁有玫瑰、有綠蔭、有寧靜的港灣,我是不系之舟。共勉 ??。
