以下是針對Java性能優化的面試題,涵蓋前后端技術棧的常見優化方式,適合評估候選人對性能調優的理解和實際應用能力:
1. JVM性能調優
題目:
- 請說明JVM垃圾回收(GC)的常見類型及其適用場景,并描述如何通過JVM參數優化GC性能。
- 編寫一個代碼示例,模擬內存泄漏場景,并說明如何通過工具定位和修復該問題。
參考答案:
-
GC類型與適用場景:
- Serial GC:單線程,適用于單核CPU的小型應用。
- Parallel GC(吞吐量優先):多線程,適用于注重吞吐量的批處理任務。
- CMS(低延遲):以最短停頓時間為目標,適用于實時系統。
- G1(平衡吞吐與延遲):適用于大堆內存(>4GB)的高并發場景。
- ZGC/RHGC(超低延遲):毫秒級停頓,適用于大內存低延遲場景(如金融交易系統)。
-
JVM參數優化示例:
# 啟用G1 GC,設置最大堆內存4GB,控制GC停頓時間目標為200ms java -XX:+UseG1GC -Xms4g -Xmx4g -XX:MaxGCPauseMillis=200 -jar myapp.jar
-
內存泄漏示例與修復:
// 內存泄漏場景:未關閉的資源導致對象無法回收 public class LeakExample {private static List<BufferedReader> readers = new ArrayList<>();public void loadData(String filePath) throws IOException {BufferedReader reader = new BufferedReader(new FileReader(filePath));readers.add(reader); // 靜態集合導致reader無法被回收// ... 使用reader ...} }
修復方法:
- 使用
try-with-resources
自動關閉資源。 - 避免靜態集合長期持有對象引用。
定位工具:
- MAT(Memory Analyzer):分析堆轉儲(heap dump),查找內存泄漏嫌疑對象。
- jstat/jmap:監控GC行為和堆內存使用情況。
- 使用
2. 高并發場景下的線程池優化
題目:
- 請說明線程池核心參數的作用,并解釋如何根據任務類型(計算密集型 vs I/O密集型)調整線程池大小。
- 編寫一個線程池配置示例,模擬高并發訂單處理場景,并說明其優化邏輯。
參考答案:
-
線程池核心參數:
corePoolSize
:核心線程數,常駐線程數量。maximumPoolSize
:最大線程數,任務激增時的擴展上限。keepAliveTime
:空閑線程存活時間。workQueue
:任務隊列,用于緩沖等待執行的任務。threadFactory
:線程工廠,自定義線程名稱或優先級。
-
線程池大小計算公式:
- 計算密集型:
線程數 = CPU核心數 + 1
- I/O密集型:
線程數 = CPU核心數 × (1 + 平均等待時間/平均工作時間)
- 計算密集型:
-
訂單處理線程池示例:
// 高并發訂單處理場景:I/O密集型任務(如遠程服務調用) int corePoolSize = Runtime.getRuntime().availableProcessors() * 2; ExecutorService executor = new ThreadPoolExecutor(corePoolSize,corePoolSize * 2,60L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(1000),new ThreadFactoryBuilder().setNameFormat("order-pool-%d").build(),new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略:由調用線程處理 );
-
優化邏輯:
- 使用有界隊列(
LinkedBlockingQueue
)防止內存溢出。 - 通過拒絕策略(
CallerRunsPolicy
)避免任務丟失。 - 監控線程池狀態(如
ThreadPoolTaskExecutor
的getTaskCount()
)。
- 使用有界隊列(
3. 數據庫與SQL優化
題目:
- 請列舉數據庫查詢性能優化的常見手段,并說明索引的優缺點。
- 編寫一個SQL查詢示例,模擬訂單分頁查詢的性能瓶頸,并說明如何優化。
參考答案:
-
數據庫優化手段:
- 索引優化:在頻繁查詢的字段(如主鍵、外鍵)創建索引。
- 分庫分表:水平分表(如按時間分片)或垂直分庫(按業務模塊拆分)。
- 連接池配置:使用
HikariCP
減少連接創建開銷。 - 批量操作:使用
batchInsert
減少網絡往返。 - 讀寫分離:主庫寫入,從庫讀取,降低主庫壓力。
-
索引的優缺點:
- 優點:加速查詢,減少全表掃描。
- 缺點:增加寫入開銷,占用額外存儲空間。
-
分頁查詢優化示例:
-- 傳統分頁(性能差) SELECT * FROM orders WHERE user_id = 1 ORDER BY create_time DESC LIMIT 10 OFFSET 100000;-- 優化方案:基于游標的分頁(適用于有序數據) SELECT * FROM orders WHERE user_id = 1 AND create_time < '2025-06-16' ORDER BY create_time DESC LIMIT 10;
-
優化邏輯:
- 避免
OFFSET
在大數據量下的性能問題。 - 利用上次查詢的
create_time
作為游標條件。
- 避免
4. 緩存策略(Redis & 本地緩存)
題目:
- 請說明Redis緩存穿透、擊穿、雪崩的解決方法,并編寫一個本地緩存(如Caffeine)的代碼示例。
- 描述如何設計一個高并發場景下的緩存預熱策略。
參考答案:
-
緩存問題與解決方案:
- 緩存穿透:惡意查詢不存在的數據 → 布隆過濾器攔截非法請求。
- 緩存擊穿:熱點數據過期 → 互斥鎖(
Redis.setnx
)或永不過期策略。 - 緩存雪崩:大量緩存同時失效 → 隨機過期時間 + 熔斷降級(如Hystrix)。
-
本地緩存示例(Caffeine):
// 使用Caffeine構建本地緩存,最大條目數1000,過期時間10分鐘 Cache<String, Object> cache = Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(10, TimeUnit.MINUTES).build();public Object getData(String key) {return cache.get(key, k -> fetchFromDB(k)); // 命中緩存或回源 }
-
緩存預熱策略:
- 定時任務預熱:在業務低峰期加載熱點數據到緩存。
- 冷啟動預熱:服務啟動時批量加載核心數據(如商品庫存)。
- 監控驅動預熱:根據歷史訪問日志動態加載數據。
5. 前端性能優化
題目:
- 請列舉前端性能優化的常見手段,并說明CDN和HTTP/2的作用。
- 編寫一個代碼示例,模擬資源加載優化(如懶加載、資源合并)。
參考答案:
-
前端優化手段:
- 減少HTTP請求:合并CSS/JS文件,使用CSS Sprites。
- 資源壓縮:Gzip壓縮HTML/CSS/JS,WebP格式圖片。
- 懶加載:延遲加載非首屏資源(如圖片、組件)。
- CDN加速:將靜態資源分發到全球節點,減少網絡延遲。
- HTTP/2:多路復用、頭部壓縮,減少請求延遲。
-
資源加載優化示例:
<!-- 圖片懶加載 --> <img src="placeholder.jpg" data-src="image.jpg" class="lazyload"><!-- 動態加載腳本 --> <script>function loadScript(src) {const script = document.createElement('script');script.src = src;script.async = true;document.head.appendChild(script);}window.addEventListener('scroll', () => {if (isInViewport('.lazyload')) {loadScript('main.js');}}); </script>
-
CDN與HTTP/2作用:
- CDN:通過就近節點提供靜態資源,降低延遲。
- HTTP/2:支持并行加載資源,減少TCP連接數,提升頁面加載速度。
6. 異步處理與消息隊列
題目:
- 請說明異步處理的優勢,并描述如何使用消息隊列(如Kafka)優化系統性能。
- 編寫一個Spring Boot中使用
@Async
注解的代碼示例。
參考答案:
-
異步處理優勢:
- 解耦業務流程(如訂單創建與短信通知)。
- 提升響應速度(避免同步阻塞)。
- 平滑流量高峰(削峰填谷)。
-
消息隊列優化場景:
- Kafka:用于日志收集、訂單異步處理,支持高吞吐量。
- RabbitMQ:用于實時任務(如支付通知)。
-
Spring Boot異步示例:
@Configuration @EnableAsync public class AsyncConfig {@Bean(name = "taskExecutor")public Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(4);executor.setMaxPoolSize(8);executor.setQueueCapacity(100);executor.setThreadNamePrefix("async-pool-");executor.initialize();return executor;} }@Service public class AsyncService {@Async("taskExecutor")public void sendNotification(String message) {// 模擬耗時操作try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("Sent: " + message);} }
-
使用場景:
- 用戶注冊后發送郵件/短信。
- 日志記錄、數據統計等后臺任務。
7. 微服務性能優化
題目:
- 請說明微服務架構中的常見性能瓶頸,并描述如何通過服務治理(如熔斷、限流)優化性能。
- 編寫一個Resilience4j熔斷器的代碼示例。
參考答案:
-
性能瓶頸與治理:
- 服務依賴鏈過長:引入分布式追蹤(如SkyWalking)。
- 雪崩效應:熔斷(Hystrix/Resilience4j)隔離故障服務。
- 突發流量:限流(令牌桶算法)保護核心服務。
-
Resilience4j熔斷器示例:
// 配置熔斷器(失敗率閾值50%,最小請求數10) Resilience4jConfig config = Resilience4jConfig.custom().failureRateThreshold(50).minimumNumberOfCalls(10).waitDuration(10, TimeUnit.SECONDS).build();// 應用熔斷器 @Bean public CircuitBreaker circuitBreaker(CircuitBreakerConfig config) {return CircuitBreaker.of("orderService", config); }@Service public class OrderService {@CircuitBreaker(name = "orderService", fallbackMethod = "fallback")public String getOrderDetails(String orderId) {// 調用遠程服務return restTemplate.getForObject("http://order-service/" + orderId, String.class);}public String fallback(Throwable t) {return "Fallback response for order details";} }
-
優化邏輯:
- 當失敗率超過閾值時,熔斷器打開,直接返回降級響應。
- 結合限流(
RateLimiter
)防止突發流量壓垮服務。
總結
以上題目覆蓋了Java性能優化的核心領域,包括JVM調優、高并發處理、數據庫優化、緩存策略、前后端資源加載、異步處理及微服務治理。通過這些問題,可以全面評估候選人對性能瓶頸的分析能力、優化手段的應用經驗以及實際編碼能力。