本文整理自阿里內部面試真題,涵蓋 Java 並發編程、鎖機制、集合框架、JVM 底層、Spring AOP、數據庫優化、事務隔離、Spring 組件掃描等 12 大高頻考點。每題附帶核心知識點、源碼級分析與實戰最佳實踐,助你在大廠面試中脫穎而出。
方法內部頻繁 append,方法返回 toString(),多線程並發訪問,選 StringBuffer 還是 StringBuilder?
選 StringBuffer。原因:StringBuffer 所有公共方法均以 synchronized 修飾,線程安全;StringBuilder 無鎖,效率高但非線程安全。多線程共享同一實例時,必須保證原子性,否則會出現內容錯亂、索引越界等問題。
// StringBuffer
public synchronized StringBuffer append(String str) { ... }
// StringBuilder
public StringBuilder append(String str) { ... } // 無 synchronized
StringBuilder,無鎖開銷,效能最優。StringConcatFactory,+ 拼接底層已優化為 invokedynamic,單線程場景下 StringBuilder 甚至非必需。Java 關鍵字,隱式監視器鎖,可重入。修飾方法/代碼塊時,保證同一時刻僅有一線程執行該臨界區。
| 修飾位置 | 鎖對象 | 適用場景 | 代碼示例 |
|---|---|---|---|
| 實例方法 | 當前實例 this | 保護實例狀態 | public synchronized void m() {} |
| 靜態方法 | 當前 Class 對象 Xxx.class | 保護類級別共享資源 | public static synchronized void m() {} |
| 同步代碼塊 (對象鎖) | 括號內指定對象 | 縮小鎖粒度、非 this 鎖 | synchronized(obj) {} |
| 同步代碼塊 (類鎖) | Xxx.class | 類級別資源競爭 | synchronized(Xxx.class) {} |
文章附帶三組完整運行結果,驗證了:synchronized(this) 僅阻塞同一實例的並發;不同實例互不干擾;靜態方法鎖住 Class,跨實例也互斥。
lock():阻塞獲取鎖,可被中斷 (lockInterruptibly())tryLock() / tryLock(timeout, unit):非阻塞/限時嘗試獲取,避免死等unlock():釋放鎖,必須在 finally 中調用newCondition():支持多條件變量,精準喚醒ReentrantLock 提供「可中斷、超時獲取、公平鎖選項、多 Condition」等高級特性,適用於複雜併發控制場景;synchronized 語法簡潔、JVM 原生優化 (偏向鎖/輕量級鎖/重量級鎖升級)、無需手動 unlock,適用於簡單同步。
| 方案 | 核心組件 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|
| 基於數據庫 | 唯一索引 / SELECT FOR UPDATE | 無額外依賴、強一致 | 性能差、單點風險 | 低併發、強一致業務 (扣款) |
| Redis 分佈式鎖 | SET NX PX + Lua 腳本 / Redisson | 高性能、支持紅鎖、看門狗續期 | 需處理主從切換一致性 | 高併發、非極強一致 (秒殺、防重) |
| ZooKeeper / etcd | 臨時有序節點 / Lease | 強一致、自動釋放、監聽機制 | 寫性能受限、運維複雜 | 配置管理、領導者選舉、強一致協調 |
| 本地鎖 + 消息隊列 | 本地 synchronized + RocketMQ 事務消息 | 極高吞吐、最終一致 | 邏輯複雜、需冪等設計 | 高吞吐、允許最終一致 (訂單異步處理) |
// 加鎖
String lockKey = "lock:order:" + orderId;
boolean success = redisTemplate.opsForValue()
.setIfAbsent(lockKey, threadId, 30, TimeUnit.SECONDS);
if (!success) return false;
// 續期看門狗 (另一線程)
while (holdLock) {
redisTemplate.expire(lockKey, 30, TimeUnit.SECONDS);
Thread.sleep(10_000);
}
// 釋放鎖 (Lua 保證原子性)
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(lockKey), threadId);
「先嘗試更新,失敗再重試」,不加鎖,通過版本號或 CAS 比對實現無鎖併發控制。
version INT DEFAULT 0,更新時 UPDATE t SET val=?, version=version+1 WHERE id=? AND version=?,影響行數=0 表示衝突。AtomicInteger、LongAdder、數據庫 WHERE col = expected。AtomicStampedReference 或版本號雙重校驗。同一請求重複執行多次,對系統狀態的影響與執行一次相同。
| 層級 | 方案 | 關鍵點 |
|---|---|---|
| 前端 | 按鈕置灰、防抖節流 | 體驗優化,不可靠 |
| 網關 | Request-Id 去重 (Redis SetNX + TTL) | 攔截 90%+ 重複流量 |
| 業務層 | 唯一索引 (訂單號)、Token 機制 (下單前申請 Token、下單時驗證刪除) | 核心保障,數據庫級約束 |
| 數據層 | 樂觀鎖版本號、狀態機流轉 (只允許 INIT→PAID) | 防止並發更新覆蓋 |
採用「前置 Token + 數據庫唯一索引 + 狀態機」三層防線:下單前調用 /token/apply 獲取 UUID 存 Redis (5min TTL);下單攜帶 Token,Service 層 DELETE FROM token WHERE token=? AND user_id=? 成功才執行業務;訂單表 UNIQUE KEY uk_biz_no (biz_no) 兜底。
execution(), @annotation() 等) 精準匹配連接點。ProxyFactory, AdvisedSupport, MethodInterceptor, InvocationHandler (JDK)。| 維度 | HashMap (JDK 8) | ConcurrentHashMap (JDK 8) |
|---|---|---|
| 線程安全 | 非線程安全 | 線程安全 (CAS + synchronized) |
| 數據結構 | 數組 + 鏈表/紅黑樹 | 數組 + 鏈表/紅黑樹 + Node<K,V>[] |
| 擴容機制 | 單線程 2倍擴容 | 多線程協助擴容 (ForwardingNode) |
| 鎖粒度 | 無鎖 | 鏈表頭節點 synchronized (JDK 8 捨棄 Segment) |
| Null 支持 | 允許 1 null key、多 null value | key/value 均不允許 null |
| 遍歷一致性 | 快速失效 | 弱一致性迭代器 |
| 性能場景 | 單線程、高頻讀寫 | 高併發讀寫、計數器、緩存 |
| 類別 | 代表類 | 核心用途 |
|---|---|---|
| 線程池 | ThreadPoolExecutor, ScheduledThreadPoolExecutor, ForkJoinPool | 任務調度、異步處理、分治計算 |
| 同步器 | CountDownLatch, CyclicBarrier, Semaphore, Phaser, Exchanger | 協調多線程步驟、限流、資源互換 |
| 鎖 | ReentrantLock, ReentrantReadWriteLock, StampedLock | 細粒度同步、讀寫分離、樂觀讀 |
| 併發集合 | ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue, BlockingQueue 族 | 高併發容器、生產消費隊列 |
| 原子類 | AtomicInteger, LongAdder, AtomicReference, LongAccumulator | 無鎖計數、CAS 更新 |
| Future/Completion | FutureTask, CompletableFuture, CompletionStage | 異步編排、組合、異常處理 |
SELECT *、優化 JOIN 順序、使用 EXPLAIN 分析執行計劃、覆蓋索引、延遲關聯。innodb_buffer_pool_size 設為物理內存 60-70%、調整 innodb_flush_log_at_trx_commit 平衡性能與持久化。ANALYZE TABLE 更新統計信息,OPTIMIZE TABLE 整理碎片。| 隔離級別 | 髒讀 | 不可重複讀 | 幻讀 | MySQL 默認 |
|---|---|---|---|---|
| READ UNCOMMITTED | Y | Y | Y | |
| READ COMMITTED | N | Y | Y | |
| REPEATABLE READ | N | N | Y (MVCC 緩解) | ✓ |
| SERIALIZABLE | N | N | N |
IDCM 專案實踐:核心交易採用 REPEATABLE READ + 顯式鎖 (SELECT ... FOR UPDATE) 保證一致性;報表查詢開啟 READ COMMITTED 避免間隙鎖影響並發;長事務拆分為短事務 + 補償機制 (TCC/Saga)。
| 注解 | 語義層級 | 特殊處理 | 典型用途 |
|---|---|---|---|
| @Component | 通用組件 | 無 | 工具類、通用 Bean |
| @Repository | 持久層 | 自動轉換持久化異常 (PersistenceExceptionTranslator) | DAO、Mapper |
| @Service | 業務層 | 無 (語義標識) | Service 實現類 |
| @Controller | 表現層 | Spring MVC 請求映射掃描、@ResponseBody 支持 | REST Controller |
<context:component-scan base-package="com.idcm">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:exclude-filter type="regex" expression="com\.idcm\.test\..*"/>
</context:component-scan>
IDCM 專案採用「基包掃描 + 註解過濾 + 排除測試包」策略,啟動速度提升 30%。
這 12 道題貫穿了 Java 後端開發的核心技術棧。面試時,「原理清晰、源碼可追、場景落地、優缺點對比」是拿到高評價的關鍵。建議針對薄弱環節專項突擊,結合項目實戰經驗構建自己的答案庫。