華為又招了一名天才少年。
共 19702字,需瀏覽 40分鐘
·
2024-04-19 14:44
大家好,我是二哥呀。
今天在微信看一看中刷到一條電子科技大學的帖子:“華為天才少年+1”,這應該是 2024 年我看到的第一個公開資料的天才少年,蕪湖,又一個百萬年薪選手即將登場。
劉順程,本科畢業(yè)于重慶郵電大學,2020 年獲得電子科技大學碩博連讀。郵電、成電的同學們看到這是不是又多了幾分學習的熱情?
要知道,華為天才少年要經(jīng)歷十幾輪的面試篩選,要求非??量?,我只能說成電還是牛的啊。劉同學剛畢業(yè)就能拿到百萬年薪,人生也算是走上了一個新的高度。
相信有不少同學對華為是情有獨鐘,那今天繼續(xù)給大家分享一個 Java 面試指南中《華為面經(jīng)-同學 9》的通用軟件開發(fā)一面原題,來看看華為面試官都喜歡問哪些問題,好做到知彼知己百戰(zhàn)不殆。
內(nèi)容較長,建議正在準備 24 屆春招和 25 屆暑期實習、秋招的同學先收藏起來,面試的時候大概率會碰到,我會盡量用通俗易懂+手繪圖的方式,讓天下所有的面渣都能逆襲 ??
1、二哥的 Linux 速查備忘手冊.pdf 下載 2、24 屆春招信息匯總表更新辣 ?? 3、三分惡面渣逆襲在線版:https://javabetter.cn/sidebar/sanfene/nixi.html
華為面經(jīng)(詳細)
介紹項目,技術(shù)選型主要問了MySQL、Redis、RabbitMQ
技術(shù)派是一個基于 Spring Boot、MyBatis-Plus、MySQL、Redis、ElasticSearch、MongoDB、Docker、RabbitMQ 等技術(shù)棧實現(xiàn)的社區(qū)系統(tǒng)。
這個系統(tǒng)旨在為創(chuàng)作者提供一個可以發(fā)布文章和教程,并賺取傭金的社區(qū)平臺,同時又兼顧一些社交屬性,比如說用戶可以通過閱讀、點贊、收藏、評論的形式和作者互動。
與此同時,為了緊跟時代潮流,該系統(tǒng)還為用戶提供了一套基于 OpenAI、訊飛星火等多家大模型的派聰明 AI 助手,幫助用戶在工作和學習中大幅提效。
選擇 MySQL 是因為它是互聯(lián)網(wǎng)主流的關(guān)系型數(shù)據(jù)庫,能夠幫助我在工作后快速承接公司的開發(fā)任務;而 Redis 作為緩存中間件,支持集群、分片,單機就可以支持數(shù)十萬 QPS,可以大大提高系統(tǒng)性能;選擇 RabbitMQ 是因為社區(qū)活躍度高,然后 RabbitMQ 還提供了一個易用的用戶界面,可以讓用戶監(jiān)控和管理消息。
手畫Netty原理和流程
Netty 是一個基于Java NIO的高性能異步事件驅(qū)動的網(wǎng)絡(luò)應用框架,極大簡化了網(wǎng)絡(luò)編程的復雜性。
常用于構(gòu)建 RPC 框架,以提升分布式服務之間的通信效率。像 Dubbo 的網(wǎng)絡(luò)層就可以基于 Netty 來實現(xiàn)。
Netty 支持零拷貝、可拓展事件模型;支持 TCP、UDP、HTTP、WebSocket 等多種協(xié)議;提供安全傳輸、可壓縮、大文件、編解碼等多種功能。
Netty 是基于主從 Reactor 模式實現(xiàn)的,主要分為兩個線程組:
①、主 Reactor 線程組(Boss Group)
負責處理新的客戶端連接請求。它內(nèi)部維護一個或多個線程,每個線程都包含一個 Selector。
ServerSocketChannel 注冊到 BossGroup 的 Selector 上,只關(guān)注 OP_ACCEPT 事件,即新的連接建立請求。
當 BossGroup 的 Selector 接收到連接請求時,使用 ServerSocketChannel.accept() 方法來接受新連接。
接受到的新連接被封裝為 NioSocketChannel,并注冊到 Worker Group 的 Selector 上。
②、從 Reactor 線程組(Worker Group)
WorkerGroup 管理的線程可能有多個,每個線程也是維護自己的 Selector。Netty 通常會根據(jù)一定的策略(如輪詢)選擇一個 Selector 來平衡負載。
每個 Selector 負責監(jiān)聽和處理所有已注冊的 NioSocketChannel 的 IO 事件,如讀 (OP_READ)、寫 (OP_WRITE) 事件等。
當事件發(fā)生時,相應的 ChannelHandler 被調(diào)用來處理這些事件。這些 Handler 可以是用戶自定義的處理器,用于實現(xiàn)具體的業(yè)務邏輯。
請說一下 Netty 的工作流程?
下面是一個簡單的 Netty 服務器和客戶端的示例,展示了基本的工作流程。這個例子中,服務器接收字符串消息,轉(zhuǎn)換為大寫形式后返回給客戶端。
NettyServer:
public class NettyServer {
private final int port;
public NettyServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new ServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = bootstrap.bind(port).sync();
System.out.println("Server started on port " + port);
future.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new NettyServer(8080).start();
}
static class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
String input = (String) msg;
System.out.println("Received: " + input);
ctx.writeAndFlush(input.toUpperCase());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
}
①、BossGroup 和 WorkerGroup:
服務器初始化時,首先創(chuàng)建兩個 NioEventLoopGroup 實例。
BossGroup 用于接受客戶端的連接,WorkerGroup 用于處理連接后的數(shù)據(jù)傳輸。
-
BossGroup 監(jiān)聽端口上的連接請求,每當接收到新連接時,BossNioEventLoop 就會處理連接請求,接受連接,并將新的 SocketChannel 注冊到 WorkerGroup 的一個 NioEventLoop 上。 -
當 WorkerGroup 的 NioEventLoop 監(jiān)測到 IO 事件(如讀取數(shù)據(jù)),它會根據(jù)注冊的 ChannelPipeline 中的 ChannelHandlers 處理這些事件。在示例中,服務器端收到數(shù)據(jù)后,通過一個 ServerHandler 將數(shù)據(jù)轉(zhuǎn)換為大寫并返回給客戶端。
②、ServerBootstrap:配置服務器使用的輔助啟動類。設(shè)置服務器要使用的 channel 類型為 NioServerSocketChannel。
并為新接入的連接定義 ChannelInitializer,在這個初始化器中,配置 ChannelPipeline,包括編解碼器和業(yè)務處理器。
NettyClient:
public class NettyClient {
private final String host;
private final int port;
public NettyClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new ClientHandler());
}
});
Channel channel = bootstrap.connect(host, port).sync().channel();
Scanner scanner = new Scanner(System.in);
while (true) {
String line = scanner.nextLine();
if ("quit".equalsIgnoreCase(line)) {
channel.close();
break;
}
channel.writeAndFlush(line);
}
channel.closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new NettyClient("localhost", 8080).start();
}
static class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
System.out.println("Received from server: " + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
}
①、EventLoopGroup:客戶端只需要一個 NioEventLoopGroup 來處理所有操作,包括創(chuàng)建連接、發(fā)送數(shù)據(jù)和接收數(shù)據(jù)。
②、Bootstrap:配置客戶端使用的輔助啟動類。設(shè)置客戶端要使用的 channel 類型為 NioSocketChannel。
客戶端使用 Scanner 從命令行讀取用戶輸入,發(fā)送到服務器;同時,它也能接收服務器返回的數(shù)據(jù),并通過 ClientHandler 打印到控制臺。
JRE與JDK的區(qū)別,JDK多了哪些東西,既安裝了JRE又安裝了JDK,可以利用JDK做什么事情?
JVM:Java Virtual Machine,也就是 Java 虛擬機,是 Java 實現(xiàn)跨平臺的關(guān)鍵所在,針對不同的操作系統(tǒng),有不同的 JVM 實現(xiàn)。JVM 負責將 Java 字節(jié)碼轉(zhuǎn)換為特定平臺的機器碼,并執(zhí)行。
JRE:Java Runtime Environment,也就是 Java 運行時環(huán)境,包含了運行 Java 程序所必需的庫,以及 Java 虛擬機(JVM)。
JDK:Java Development Kit,是一套完整的 Java SDK(軟件開發(fā)工具包),包括了 JRE 以及編譯器(javac)、Java 文檔生成工具(Javadoc)、Java 調(diào)試器等開發(fā)工具。為開發(fā)者提供了開發(fā)、編譯、調(diào)試 Java 程序的一整套環(huán)境。
簡單來說,JDK 包含 JRE,JRE 包含 JVM。
如何排查OOM?
內(nèi)存溢出(Out of Memory,俗稱 OOM)是指當程序請求分配內(nèi)存時,由于沒有足夠的內(nèi)存空間滿足其需求,從而觸發(fā)的錯誤。
首先,我會通過異常信息和日志確定OOM的類型。Java的OOM錯誤通常有幾種類型,如堆內(nèi)存溢出、Metaspace溢出或直接內(nèi)存溢出。比如,如果日志中顯示“java.lang.OutOfMemoryError: Java heap space”,那就說明是堆內(nèi)存溢出。
一旦確定了是堆內(nèi)存溢出,我會使用 JConsole 實時監(jiān)控JVM的內(nèi)存使用情況,特別是那些占用大量內(nèi)存的對象和類。
找到可能的內(nèi)存泄漏源后,我會回到代碼中去,查找和修復具體的問題。
之后,我會在本地進行壓力測試,模擬高負載情況下的內(nèi)存表現(xiàn),確保修改有效,且沒有引入新的問題。
如何查看當前Java程序里哪些對象正在使用,哪些對象已經(jīng)被釋放
在 Java 程序中,查看哪些對象正在使用和哪些已經(jīng)被釋放的方法主要涉及運行時的內(nèi)存監(jiān)控和分析。需要借助一些專門的工具來進行:
①、JConsole:JDK 自帶的監(jiān)控工具,可以用來監(jiān)視 Java 應用程序的運行狀態(tài),包括內(nèi)存使用、線程狀態(tài)、類加載、GC 等,還可以進行一些基本的性能分析。
②、VisualVM:VisualVM 是一個基于 NetBeans 平臺的可視化工具,在很長一段時間內(nèi),VisualVM 都是 Oracle 官方主推的故障處理工具。集成了多個 JDK 命令行工具的功能,提供了一個友好的圖形界面,非常適用于開發(fā)和生產(chǎn)環(huán)境。
③、Java Mission Control:JMC 最初是 JRockit VM 中的診斷工具,但在 Oracle JDK7 Update 40 以后,就綁定到了 HotSpot VM 中。不過后來又被 Oracle 開源出來作為一個單獨的產(chǎn)品。
還有一些第三方的工具:
①、MAT:
-
Java 堆內(nèi)存分析工具,主要用于分析和查找 Java 堆中的內(nèi)存泄漏和內(nèi)存消耗問題。 -
可以從 Java 堆轉(zhuǎn)儲文件中分析內(nèi)存使用情況,并提供豐富的報告,如內(nèi)存泄漏疑點、最大對象和 GC 根信息。 -
支持通過圖形界面查詢對象,以及檢查對象間的引用關(guān)系。
②、GChisto:GC 日志分析工具,幫助開發(fā)者優(yōu)化垃圾收集行為和調(diào)整 GC 性能。
③、GCViewer:類似于 GChisto,也是用來分析 GC 日志,幫助開發(fā)者優(yōu)化 Java 應用的垃圾回收過程。
④、JProfiler:一個全功能的商業(yè) Java 性能分析工具,提供 CPU、 內(nèi)存和線程的實時分析。
⑤、arthas:
-
阿里巴巴開源的 Java 診斷工具,主要用于線上的應用診斷。 -
支持在不停機的情況下進行 Java 應用的診斷。 -
包括 JVM 信息查看、監(jiān)控、Trace 命令、反編譯等。
⑥、async-profiler:一個低開銷的性能分析工具,支持生成火焰圖,適用于復雜性能問題的分析。
Java緩沖區(qū)溢出,如何預防
Java 緩沖區(qū)溢出主要是由于向緩沖區(qū)寫入的數(shù)據(jù)超過其能夠存儲的數(shù)據(jù)量。可以采用這些措施來避免:
①、合理設(shè)置緩沖區(qū)大小:在創(chuàng)建緩沖區(qū)時,應根據(jù)實際需求合理設(shè)置緩沖區(qū)的大小,避免創(chuàng)建過大或過小的緩沖區(qū)。
②、控制寫入數(shù)據(jù)量:在向緩沖區(qū)寫入數(shù)據(jù)時,應該控制寫入的數(shù)據(jù)量,確保不會超過緩沖區(qū)的容量。Java 的 ByteBuffer 類提供了remaining()方法,可以獲取緩沖區(qū)中剩余的可寫入數(shù)據(jù)量。
import java.nio.ByteBuffer;
public class ByteBufferExample {
public static void main(String[] args) {
// 模擬接收到的數(shù)據(jù)
byte[] receivedData = {1, 2, 3, 4, 5};
int bufferSize = 1024; // 設(shè)置一個合理的緩沖區(qū)大小
// 創(chuàng)建ByteBuffer
ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
// 寫入數(shù)據(jù)之前檢查容量是否足夠
if (buffer.remaining() >= receivedData.length) {
buffer.put(receivedData);
} else {
System.out.println("Not enough space in buffer to write data.");
}
// 準備讀取數(shù)據(jù):將limit設(shè)置為當前位置,position設(shè)回0
buffer.flip();
// 讀取數(shù)據(jù)
while (buffer.hasRemaining()) {
byte data = buffer.get();
System.out.println("Read data: " + data);
}
// 清空緩沖區(qū)以便再次使用
buffer.clear();
}
}
進程和線程的區(qū)別
進程說簡單點就是我們在電腦上啟動的一個個應用,比如我們啟動一個瀏覽器,就會啟動了一個瀏覽器進程。進程是操作系統(tǒng)資源分配的最小單位,它包括了程序、數(shù)據(jù)和進程控制塊等。
線程說簡單點就是我們在 Java 程序中啟動的一個 main 線程,一個進程至少會有一個線程。當然了,我們也可以啟動多個線程,比如說一個線程進行 IO 讀寫,一個線程進行加減乘除計算,這樣就可以充分發(fā)揮多核 CPU 的優(yōu)勢,因為 IO 讀寫相對 CPU 計算來說慢得多。線程是 CPU 分配資源的基本單位。
一個進程中可以有多個線程,多個線程共用進程的堆和方法區(qū)(Java 虛擬機規(guī)范中的一個定義,JDK 8 以后的實現(xiàn)為元空間)資源,但是每個線程都會有自己的程序計數(shù)器和棧。
進程的調(diào)度方式
進程調(diào)度是操作系統(tǒng)中的核心功能之一,它負責決定哪些進程在何時使用 CPU。這一決定基于系統(tǒng)中的進程調(diào)度算法。
①、先來先服務
這是最簡單的調(diào)度算法,也稱為先進先出(FIFO)。進程按照請求 CPU 的順序進行調(diào)度。這種方式易于實現(xiàn),但可能會導致較短的進程等待較長進程執(zhí)行完成,從而產(chǎn)生“饑餓”現(xiàn)象。
②、短作業(yè)優(yōu)先
選擇預計運行時間最短的進程優(yōu)先執(zhí)行。這種方式可以減少平均等待時間和響應時間,但缺點是很難準確預知進程的執(zhí)行時間,并且可能因為短作業(yè)一直在執(zhí)行,導致長作業(yè)持續(xù)被推遲執(zhí)行。
③、優(yōu)先級調(diào)度
在這種調(diào)度方式中,每個進程都被分配一個優(yōu)先級。CPU 首先分配給優(yōu)先級最高的進程。優(yōu)先級調(diào)度可以是非搶占式的或搶占式的。在非搶占式優(yōu)先級調(diào)度中,進程一旦開始執(zhí)行將一直運行直到完成;在搶占式優(yōu)先級調(diào)度中,更高優(yōu)先級的進程可以中斷正在執(zhí)行的低優(yōu)先級進程。
④、時間片輪轉(zhuǎn)
時間片輪轉(zhuǎn)調(diào)度為每個進程分配一個固定的時間段,稱為時間片,進程可以在這個時間片內(nèi)運行。如果進程在時間片結(jié)束時還沒有完成,它將被放回隊列的末尾。時間片輪轉(zhuǎn)是公平的調(diào)度方式,可以保證所有進程得到公平的 CPU 時間,適用于共享系統(tǒng)。
⑤、最短剩余時間優(yōu)先
這是短作業(yè)優(yōu)先的一種改進形式,它是搶占式的。即如果一個新進程的預計執(zhí)行時間比當前運行進程的剩余時間短,調(diào)度器將暫停當前的進程,并切換到新進程。這種方法也可以最小化平均等待時間,但同樣面臨預測執(zhí)行時間的困難。
參考鏈接
-
三分惡的面渣逆襲:https://javabetter.cn/sidebar/sanfene/nixi.html -
二哥的 Java 進階之路:https://javabetter.cn
ending
一個人可以走得很快,但一群人才能走得更遠。二哥的編程星球已經(jīng)有 5100 多名球友加入了,如果你也需要一個良好的學習環(huán)境,戳鏈接 ?? 加入我們吧。這是一個編程學習指南 + Java 項目實戰(zhàn) + LeetCode 刷題的私密圈子,你可以閱讀星球?qū)凇⑾蚨缣釂?、幫你制定學習計劃、和球友一起打卡成長。
兩個置頂帖「球友必看」和「知識圖譜」里已經(jīng)沉淀了非常多優(yōu)質(zhì)的學習資源,相信能幫助你走的更快、更穩(wěn)、更遠。
歡迎點擊左下角閱讀原文了解二哥的編程星球,這可能是你學習求職路上最有含金量的一次點擊。
最后,把二哥的座右銘送給大家:沒有什么使我停留——除了目的,縱然岸旁有玫瑰、有綠蔭、有寧靜的港灣,我是不系之舟。共勉 ??。
