目錄
一、Java線程核心機制
🔥 問題3:start()與run()的底層執行差異
線程啟動流程圖解
核心差異對照表
代碼驗證示例
🔥 問題4:Thread與Runnable的六大維度對比
類關系UML圖
最佳實踐代碼
🔥 問題5:線程參數傳遞三大方案
參數傳遞方案對比
Lambda傳參最佳實踐
二、Spring依賴注入全景解析
🌟 Spring依賴注入四大方式
DI實現方式對比表
構造器注入最佳實踐
🌟 Spring自動裝配原理圖解
自動裝配注解對比
三、高頻面試題強化訓練
1. Spring為什么推薦構造器注入?
2. @Autowired與@Resource的區別?
3. 如何解決多個同類型Bean的沖突?
一、Java線程核心機制
🔥 問題3:start()與run()的底層執行差異
線程啟動流程圖解
核心差異對照表
方法 | 執行線程 | 調用次數 | JVM操作 | 典型應用場景 |
---|---|---|---|---|
start() | 新創建的子線程 | 單次 | 觸發native線程創建 | 多線程任務啟動 |
run() | 主調用線程 | 多次 | 普通Java方法調用 | 單線程測試/調試 |
代碼驗證示例
public class StartVsRun {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("當前線程: " + Thread.currentThread().getName());});thread.start(); // 輸出: Thread-0thread.run(); // 輸出: main}
}
🔥 問題4:Thread與Runnable的六大維度對比
類關系UML圖
維度 | Thread | Runnable |
---|---|---|
類型 | 具體類 | 接口 |
繼承限制 | 占用繼承名額 | 不占用 |
資源共享 | 實例變量獨立 | 可共享同一實例 |
擴展性 | 單繼承限制 | 支持多實現 |
線程池兼容性 | 需包裝為Runnable | 直接支持 |
設計模式 | 具體實現 | 策略模式 |
最佳實踐代碼
// 推薦實現方式
public class DownloadTask implements Runnable {private String url;public DownloadTask(String url) {this.url = url;}@Overridepublic void run() {// 文件下載邏輯}
}// 使用示例
ExecutorService pool = Executors.newFixedThreadPool(5);
pool.execute(new DownloadTask("https://example.com/file1"));
pool.execute(new DownloadTask("https://example.com/file2"));
🔥 問題5:線程參數傳遞三大方案
參數傳遞方案對比
方式 | 實現示例 | 優點 | 缺點 |
---|---|---|---|
構造器傳參 | new MyThread(param).start() | 線程安全 | 創建后參數不可變 |
成員變量傳參 | thread.setConfig(config) | 靈活修改 | 需處理線程可見性問題 |
回調函數傳參 | executor.submit(() -> task(param)) | Lambda簡潔 | 要求參數final或等效 |
Lambda傳參最佳實踐
public class ThreadParamDemo {public static void main(String[] args) {String config = "server.properties";// Lambda傳參(實質是閉包)new Thread(() -> loadConfig(config)).start();// 通過Future傳參ExecutorService pool = Executors.newSingleThreadExecutor();Future<String> future = pool.submit(() -> processData(config));}private static void loadConfig(String path) {// 配置文件加載邏輯}private static String processData(String input) {// 數據處理邏輯return "processed_" + input;}
}
二、Spring依賴注入全景解析
🌟 Spring依賴注入四大方式
DI實現方式對比表
注入方式 | 實現示例 | 優點 | 缺點 |
---|---|---|---|
構造器注入 | new Service(dao) | 不可變/線程安全 | 參數多時代碼冗長 |
Setter注入 | service.setDao(dao) | 靈活可選依賴 | 可能破壞不變性 |
字段注入 | @Autowired private Dao dao | 代碼簡潔 | 測試困難/隱藏依賴 |
方法注入 | @Autowired public void init(Dao dao) | 精確控制時機 | 使用頻率較低 |
構造器注入最佳實踐
@Service
public class OrderService {private final PaymentService paymentService;private final InventoryService inventoryService;@Autowiredpublic OrderService(PaymentService paymentService, InventoryService inventoryService) {this.paymentService = paymentService;this.inventoryService = inventoryService;}
}
🌟 Spring自動裝配原理圖解
自動裝配注解對比
注解 | 裝配方式 | 適用場景 | 沖突解決 |
---|---|---|---|
@Autowired | 按類型優先 | 多數單實現場景 | @Qualifier指定名稱 |
@Resource | 按名稱優先 | JNDI資源注入 | 名稱不存在時按類型 |
@Inject | 與@Autowired類似 | JSR-330標準實現 | 需要額外依賴 |
三、高頻面試題強化訓練
1. Spring為什么推薦構造器注入?
-
不可變性:確保依賴項在初始化后不變
-
循環依賴檢測:啟動時立即發現依賴問題
-
測試友好:便于通過構造器傳遞Mock對象
-
線程安全:避免并發修改依賴項
2. @Autowired與@Resource的區別?
維度 | @Autowired | @Resource |
---|---|---|
標準歸屬 | Spring專屬 | JSR-250標準 |
默認裝配策略 | 按類型 | 按名稱 |
必需性控制 | required=false | 無 |
參數指定方式 | @Qualifier | name屬性 |
應用范圍 | 字段/構造器/方法 | 字段/setter方法 |
3. 如何解決多個同類型Bean的沖突?
// 方案一:使用@Primary標記主候選
@Bean
@Primary
public DataSource masterDataSource() {return new HikariDataSource();
}// 方案二:使用@Qualifier指定名稱
@Autowired
@Qualifier("backupDataSource")
private DataSource dataSource;// 方案三:使用自定義限定注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("report")
public @interface ReportDataSource {}@Bean
@ReportDataSource
public DataSource reportDataSource() {return new DruidDataSource();
}
實戰建議:
-
在Spring Boot中通過
@ConfigurationProperties
實現類型安全配置注入 -
使用
@Lazy
注解延遲初始化資源密集型Bean -
通過
@Profile
實現環境特定的Bean裝配
💬 你在項目中更傾向于使用哪種依賴注入方式?遇到過哪些注入難題?
🎁 關注+轉發,抽送《阿里Java開發手冊》電子書