在下載任務中對整個下載方法加 synchronized,導致多線程變成串行執行,失去並發優勢,甚至出現線程「失效」現象。
synchronized 鎖住的是整個下載流程,包含網路 I/O、檔案寫入等耗時操作。這會強制所有線程排隊執行,違背多線程下載的初衷。
只同步「任務獲取」階段,不同步「下載執行」階段。
ConcurrentLinkedQueue 或 BlockingQueue)存放待下載任務。poll() 或 take() 獲取任務,獲取過程原子化,無需額外鎖。// 任務隊列(線程安全)
BlockingQueue taskQueue = new LinkedBlockingQueue<>();
// 生產者:添加任務
public void addTask(DownloadTask task) {
taskQueue.offer(task);
}
// 消費者線程:持續獲取並執行
class DownloadWorker implements Runnable {
public void run() {
while (true) {
try {
DownloadTask task = taskQueue.take(); // 阻塞直到有任務
executeDownload(task); // 此處無需 synchronized
} catch (InterruptedException e) {
break;
}
}
}
private void executeDownload(DownloadTask task) {
// 網路請求、檔案寫入等耗時操作,完全並發
}
}
鎖的粒度越細越好。下載場景下,將「任務分發」與「任務執行」解耦,利用並發容器天然的線程安全特性,即可實現高效並發下載。