快手員工薪酬一覽表。。
共 9359字,需瀏覽 19分鐘
·
2024-04-26 14:44
大家好,我是二哥呀。
2024 年 4 月 22 日,快手發(fā)布了 2023 年的年度財(cái)報(bào),從中我總結(jié)出了一些關(guān)鍵信息,覺得很有必要給同學(xué)們同步一下。
①、2023 年快手收入 1134 億元,比 2022 年多了 200 億,已經(jīng)追上百度和網(wǎng)易,可以說是妥妥的互聯(lián)網(wǎng)大廠了。(能保持營收增長的公司都是好公司啊??)
②、2023 年快手員工人數(shù)增長 1000 人,人均營收達(dá) 430 萬,僅次于鵝廠和宇宙廠。(大家可以對號入座看看自己有沒有被人均??)
③、如果不帶股權(quán)的話,2023 年快手的人均薪酬是 59.3 萬人民幣,再結(jié)合 24 屆秋招薪資的情況來看,能去大廠整體上收入還是香。
希望今年秋招快手能繼續(xù)給力,增加 HC,這樣也能給 25 屆的同學(xué)更多選擇,直播和電商是快手的核心業(yè)務(wù)組,目前 Java 后端實(shí)習(xí)崗位還比較充足,大家可以繼續(xù)沖!
接下來,我們繼續(xù)以《Java 面試指南-快手面經(jīng)》中同學(xué) 1 為例,來看看快手面試官都喜歡問哪些問題,好做到知彼知己百戰(zhàn)不殆。
多次出現(xiàn)的面試題我在面渣逆襲在線版中都有標(biāo)記??,同學(xué)們可以移步到面渣逆襲在線版或者 GitHub 開源倉庫中查看。
1、二哥的 Linux 速查備忘手冊.pdf 下載 2、三分惡面渣逆襲在線版:https://javabetter.cn/sidebar/sanfene/nixi.html 3、二哥的 Java 進(jìn)階之路 GitHub 最新版:https://github.com/itwanger/toBeBetterJavaer 4、24 屆春招急救箱更新辣 ??
快手面經(jīng)(強(qiáng)度拉滿)
Java的基礎(chǔ)數(shù)據(jù)類型,分別占多少字節(jié)
| 數(shù)據(jù)類型 | 默認(rèn)值 | 大小 |
|---|---|---|
| boolean | false | 1 比特 |
| char | '\u0000' | 2 字節(jié) |
| byte | 0 | 1 字節(jié) |
| short | 0 | 2 字節(jié) |
| int | 0 | 4 字節(jié) |
| long | 0L | 8 字節(jié) |
| float | 0.0f | 4 字節(jié) |
| double | 0.0 | 8 字節(jié) |
HashMap的結(jié)構(gòu)?
JDK 8 中 HashMap 的數(shù)據(jù)結(jié)構(gòu)是數(shù)組+鏈表+紅黑樹。
HashMap的put過程
ConcurrentHashMap 對HashMap的優(yōu)化?
ConcurrentHashMap 是 HashMap 的線程安全版本,使用了 CAS、synchronized、volatile 來確保線程安全。
首先是 hash 的計(jì)算方法上,ConcurrentHashMap 的 spread 方法接收一個(gè)已經(jīng)計(jì)算好的 hashCode,然后將這個(gè)哈希碼的高 16 位與自身進(jìn)行異或運(yùn)算,這里的 HASH_BITS 是一個(gè)常數(shù),值為 0x7fffffff,它確保結(jié)果是一個(gè)非負(fù)整數(shù)。
static final int spread(int h) {
return (h ^ (h >>> 16)) & HASH_BITS;
}
比 HashMap 的 hash 計(jì)算多了一個(gè) & HASH_BITS 的操作。
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
另外,ConcurrentHashMap 對節(jié)點(diǎn) Node 做了進(jìn)一步的封裝,比如說用 Forwarding Node 來表示正在進(jìn)行擴(kuò)容的節(jié)點(diǎn)。
static final class ForwardingNode<K,V> extends Node<K,V> {
final Node<K,V>[] nextTable;
ForwardingNode(Node<K,V>[] tab) {
super(MOVED, null, null, null);
this.nextTable = tab;
}
}
最后就是 put 方法,通過 CAS + synchronized 來保證線程安全。
ConcurrentHashMap 1.8比1.7的優(yōu)化在哪里?
ConcurrentHashMap 在 JDK 7 時(shí)采用的是分段鎖機(jī)制(Segment Locking),整個(gè) Map 被分為若干段,每個(gè)段都可以獨(dú)立地加鎖。因此,不同的線程可以同時(shí)操作不同的段,從而實(shí)現(xiàn)并發(fā)訪問。
在 JDK 8 及以上版本中,ConcurrentHashMap 的實(shí)現(xiàn)進(jìn)行了優(yōu)化,不再使用分段鎖,而是使用了一種更加精細(xì)化的鎖——桶鎖,以及 CAS 無鎖算法。每個(gè)桶(Node 數(shù)組的每個(gè)元素)都可以獨(dú)立地加鎖,從而實(shí)現(xiàn)更高級別的并發(fā)訪問。
同時(shí),對于讀操作,通常不需要加鎖,可以直接讀取,因?yàn)?ConcurrentHashMap 內(nèi)部使用了 volatile 變量來保證內(nèi)存可見性。
對于寫操作,ConcurrentHashMap 使用 CAS 操作來實(shí)現(xiàn)無鎖的更新,這是一種樂觀鎖的實(shí)現(xiàn),因?yàn)樗僭O(shè)沒有沖突發(fā)生,在實(shí)際更新數(shù)據(jù)時(shí)才檢查是否有其他線程在嘗試修改數(shù)據(jù),如果有,采用悲觀的鎖策略,如 synchronized 代碼塊來保證數(shù)據(jù)的一致性。
你對線程安全的理解是什么?
線程安全是并發(fā)編程中一個(gè)重要的概念,如果一段代碼塊或者一個(gè)方法在多線程環(huán)境中被多個(gè)線程同時(shí)執(zhí)行時(shí)能夠正確地處理共享數(shù)據(jù),那么這段代碼塊或者方法就是線程安全的。
可以從三個(gè)要素來確保線程安全:
①、原子性:確保當(dāng)某個(gè)線程修改共享變量時(shí),沒有其他線程可以同時(shí)修改這個(gè)變量,即這個(gè)操作是不可分割的。
原子性可以通過互斥鎖(如 synchronized)或原子操作(如 AtomicInteger 類中的方法)來保證。
②、可見性:確保一個(gè)線程對共享變量的修改可以立即被其他線程看到。
volatile 關(guān)鍵字可以保證了變量的修改對所有線程立即可見,并防止編譯器優(yōu)化導(dǎo)致的可見性問題。
③、活躍性問題:要確保線程不會(huì)因?yàn)樗梨i、饑餓、活鎖等問題導(dǎo)致無法繼續(xù)執(zhí)行。
請說一下Java的內(nèi)存區(qū)域,程序計(jì)數(shù)器等?
JVM 的內(nèi)存區(qū)域,有時(shí)叫 JVM 的內(nèi)存結(jié)構(gòu),有時(shí)也叫 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū),按照 Java 的虛擬機(jī)規(guī)范,可以細(xì)分為程序計(jì)數(shù)器、虛擬機(jī)棧、本地方法棧、堆、方法區(qū)等。
介紹一下程序計(jì)數(shù)器?
程序計(jì)數(shù)器(Program Counter Register)也被稱為 PC 寄存器,是一塊較小的內(nèi)存空間。它可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼行號指示器。
向線程池中提交任務(wù)的過程?
當(dāng)應(yīng)用程序提交一個(gè)任務(wù)時(shí),線程池會(huì)根據(jù)當(dāng)前線程的狀態(tài)和參數(shù)決定如何處理這個(gè)任務(wù)。
-
如果線程池中的核心線程都在忙,并且線程池未達(dá)到最大線程數(shù),新提交的任務(wù)會(huì)被放入隊(duì)列中進(jìn)行等待。 -
如果任務(wù)隊(duì)列已滿,且當(dāng)前線程數(shù)量小于最大線程數(shù),線程池會(huì)創(chuàng)建新的線程來處理任務(wù)。
空閑的線程會(huì)從任務(wù)隊(duì)列中取出任務(wù)來執(zhí)行,當(dāng)任務(wù)執(zhí)行完畢后,線程并不會(huì)立即銷毀,而是繼續(xù)保持在池中等待下一個(gè)任務(wù)。
當(dāng)線程空閑時(shí)間超出指定時(shí)間,且當(dāng)前線程數(shù)量大于核心線程數(shù)時(shí),線程會(huì)被回收。
核心線程和最大線程的區(qū)別是什么?
①、corePoolSize
定義了線程池中的核心線程數(shù)量。即使這些線程處于空閑狀態(tài),它們也不會(huì)被回收。這是線程池保持在等待狀態(tài)下的線程數(shù)。
②、maximumPoolSize
線程池允許的最大線程數(shù)量。當(dāng)工作隊(duì)列滿了之后,線程池會(huì)創(chuàng)建新線程來處理任務(wù),直到線程數(shù)達(dá)到這個(gè)最大值。
核心線程能銷毀嗎?
核心線程會(huì)一直運(yùn)行,而超出核心線程數(shù)的線程,如果空閑時(shí)間超過 keepAliveTime,將會(huì)被終止,直到線程池的線程數(shù)減少到 corePoolSize。
了解OOM嗎?
內(nèi)存泄漏:是指程序在使用完內(nèi)存后,未能釋放已分配的內(nèi)存空間,導(dǎo)致這部分內(nèi)存無法再被使用。隨著時(shí)間的推移,內(nèi)存泄漏會(huì)導(dǎo)致可用內(nèi)存逐漸減少,最終可能導(dǎo)致內(nèi)存溢出。
Java哪些內(nèi)存區(qū)域會(huì)發(fā)生OOM?為什么?
導(dǎo)致內(nèi)存溢出(OOM)的原因有很多,比如一次性創(chuàng)建了大量對象導(dǎo)致堆內(nèi)存溢出;比如說元空間溢出,拋出 java.lang.OutOfMemoryError:Metaspace,比如說棧溢出,如果棧的深度超過了 JVM 棧所允許的深度,將會(huì)拋出 StackOverflowError。
你如何排查OOM?
第一步,使用 jps 查看運(yùn)行的 Java 進(jìn)程 ID
第二步,使用top -p [pid] 查看進(jìn)程使用 CPU 和內(nèi)存占用情況
第三步,使用 top -Hp [pid] 查看進(jìn)程下的所有線程占用 CPU 和內(nèi)存情況
第四步,將線程 ID 轉(zhuǎn)換為 16 進(jìn)制:printf "%x\n" [pid],輸出的值就是線程棧信息中的 nid。
例如:
printf "%x\n" 29471,輸出 731f。
第五步,抓取線程棧:jstack 29452 > 29452.txt,可以多抓幾次做個(gè)對比。
在線程棧信息中找到對應(yīng)線程號的 16 進(jìn)制值,如下是 731f 線程的信息。線程棧分析可使用 VisualVM 插件 TDA。
"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007fbe2c164000 nid=0x731f runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
第六步,使用jstat -gcutil [pid] 5000 10 每隔 5 秒輸出 GC 信息,輸出 10 次,查看 YGC 和 Full GC 次數(shù)。
通常會(huì)出現(xiàn) YGC 不增加或增加緩慢,而 Full GC 增加很快。
或使用 jstat -gccause [pid] 5000 輸出 GC 摘要信息。
或使用 jmap -heap [pid] 查看堆的摘要信息,關(guān)注老年代內(nèi)存使用是否達(dá)到閥值,若達(dá)到閥值就會(huì)執(zhí)行 Full GC。
如果發(fā)現(xiàn) Full GC 次數(shù)太多,就很大概率存在內(nèi)存泄漏了
第八步,使用 jmap -histo:live [pid] 輸出每個(gè)類的對象數(shù)量,內(nèi)存大小(字節(jié)單位)及全限定類名。
第九步,生成 dump 文件,借助工具分析哪個(gè)對象非常多,基本就能定位到問題根源了。
使用 jmap 生成 dump 文件:
# jmap -dump:live,format=b,file=29471.dump 29471
Dumping heap to /root/dump ...
Heap dump file created
第十步,dump 文件分析
可以使用 jhat 命令分析:jhat -port 8000 29471.dump,瀏覽器訪問 jhat 服務(wù),端口是 8000。
也可以使用圖形化工具分析,如 JDK 自帶的 jvisualvm,從菜單 > 文件 > 裝入 dump 文件。
或使用第三方式具分析的,如 JProfiler、GCViewer 工具。
或使用在線分析平臺(tái) GCEasy。
注意:如果 dump 文件較大的話,分析會(huì)占比較大的內(nèi)存。
在 dump 文析結(jié)果中查找存在大量的對象,再查對其的引用?;旧暇涂梢远ㄎ坏酱a層的邏輯了。
請說一下ThreadLocal的作用和使用場景?
ThreadLocal 是 Java 中提供的一種用于實(shí)現(xiàn)線程局部變量的工具類。它允許每個(gè)線程都擁有自己的獨(dú)立副本,從而實(shí)現(xiàn)線程隔離,用于解決多線程中共享對象的線程安全問題。
假如在服務(wù)層和持久層也要用到用戶信息,就可以在控制層攔截請求把用戶信息存入 ThreadLocal。
這樣我們在任何一個(gè)地方,都可以取出 ThreadLocal 中存的用戶信息。
很多其它場景的 cookie、session 等等數(shù)據(jù)隔離都可以通過 ThreadLocal 去實(shí)現(xiàn)。
數(shù)據(jù)庫連接池也可以用 ThreadLocal,將數(shù)據(jù)庫連接池的連接交給 ThreadLocal 進(jìn)行管理,能夠保證當(dāng)前線程的操作都是同一個(gè) Connnection。
ThreadLocal有什么缺陷?
如果一個(gè)線程一直在運(yùn)行,并且其 ThreadLocalMap 中的 Entry.value 一直指向某個(gè)強(qiáng)引用對象,那么這個(gè)對象就不會(huì)被回收,從而導(dǎo)致內(nèi)存泄漏。當(dāng) Entry 非常多時(shí),可能就會(huì)引發(fā)更嚴(yán)重的內(nèi)存溢出問題。
你了解哪些ThreadLocal的改進(jìn)方案?
在 JDK 20 Early-Access Build 28 版本中,出現(xiàn)了 ThreadLocal 的改進(jìn)方案,即 ScopedValue。
還有 Netty 中的 FastThreadLocal,它是 Netty 對 ThreadLocal 的優(yōu)化,它內(nèi)部維護(hù)了一個(gè)索引常量 index,每次創(chuàng)建 FastThreadLocal 中都會(huì)自動(dòng)+1,用來取代 hash 沖突帶來的損耗,用空間換時(shí)間。
private final int index;
public FastThreadLocal() {
index = InternalThreadLocalMap.nextVariableIndex();
}
public static int nextVariableIndex() {
int index = nextIndex.getAndIncrement();
if (index < 0) {
nextIndex.decrementAndGet();
}
return index;
}
Mysql的聚簇索引和非聚簇索引的區(qū)別是什么?
聚簇索引不是一種新的索引,而是一種數(shù)據(jù)存儲(chǔ)方式。
在聚簇索引中,表中的行是按照鍵值(索引)的順序存儲(chǔ)的。這意味著表中的實(shí)際數(shù)據(jù)行和鍵值之間存在物理排序的關(guān)系。因此,每個(gè)表只能有一個(gè)聚簇索引。例如,在 MySQL 的 InnoDB 存儲(chǔ)引擎中,主鍵就是聚簇索引。
在非聚簇索引中,索引和數(shù)據(jù)是分開存儲(chǔ)的,索引中的鍵值指向數(shù)據(jù)的實(shí)際存儲(chǔ)位置。因此,非聚簇索引也被稱為二級索引或輔助索引。表可以有多個(gè)非聚簇索引。
Redis的sadd命令時(shí)間復(fù)雜度是多少?
向指定 Set 中添加 1 個(gè)或多個(gè) member,如果指定 Set 不存在,會(huì)自動(dòng)創(chuàng)建一個(gè)。時(shí)間復(fù)雜度為 O(N) ,N 為添加的 member 個(gè)數(shù)。
Redis的cluster集群如何實(shí)現(xiàn)?
在 Redis Cluster 中,數(shù)據(jù)和實(shí)例之間的映射是通過哈希槽(hash slot)來實(shí)現(xiàn)的。Redis Cluster 有 16384 個(gè)哈希槽,每個(gè)鍵根據(jù)其名字的 CRC16 值被映射到這些哈希槽上。然后,這些哈希槽會(huì)被均勻地分配到所有的 Redis 實(shí)例上。
CRC16 是一種哈希算法,它可以將任意長度的輸入數(shù)據(jù)映射為一個(gè) 16 位的哈希值。
參考鏈接
-
三分惡的面渣逆襲:https://javabetter.cn/sidebar/sanfene/nixi.html -
二哥的 Java 進(jìn)階之路:https://javabetter.cn
ending
一個(gè)人可以走得很快,但一群人才能走得更遠(yuǎn)。二哥的編程星球已經(jīng)有 5100 多名球友加入了,如果你也需要一個(gè)良好的學(xué)習(xí)環(huán)境,戳鏈接 ?? 加入我們吧。這是一個(gè)編程學(xué)習(xí)指南 + Java 項(xiàng)目實(shí)戰(zhàn) + LeetCode 刷題的私密圈子,你可以閱讀星球?qū)?、向二哥提問、幫你制定學(xué)習(xí)計(jì)劃、和球友一起打卡成長。
兩個(gè)置頂帖「球友必看」和「知識(shí)圖譜」里已經(jīng)沉淀了非常多優(yōu)質(zhì)的學(xué)習(xí)資源,相信能幫助你走的更快、更穩(wěn)、更遠(yuǎn)。
歡迎點(diǎn)擊左下角閱讀原文了解二哥的編程星球,這可能是你學(xué)習(xí)求職路上最有含金量的一次點(diǎn)擊。
最后,把二哥的座右銘送給大家:沒有什么使我停留——除了目的,縱然岸旁有玫瑰、有綠蔭、有寧靜的港灣,我是不系之舟。共勉 ??。
