1. 线程池的好处与使用场景
好处:
- 性能优化:减少频繁创建和销毁线程的开销。
- 资源管理:控制并发线程的数量,避免系统资源耗尽。
- 任务管理:提供线程的调度和复用机制。
常见使用场景:
- 执行并发任务(如批量文件处理、网络请求)。
- 实现高并发处理的服务端应用。
线程池创建方法
Java 提供了 Executors
工具类,用于创建常见的线程池:
- 固定线程池:
Executors.newFixedThreadPool(nThreads)
。 - 单线程池:
Executors.newSingleThreadExecutor()
。 - 缓存线程池:
Executors.newCachedThreadPool()
。 - 定时任务线程池:
Executors.newScheduledThreadPool(nThreads)
。
2. 使用线程池创建线程
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3); // 创建固定大小为3的线程池
for (int i = 1; i <= 5; i++) {
int taskNumber = i;
threadPool.execute(() -> {
System.out.println("任务 " + taskNumber + " 正在执行,线程:" + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
threadPool.shutdown(); // 关闭线程池
}
}
3. 并发工具类
CountDownLatch
用于等待多个线程完成任务,再继续执行主线程。
使用场景:实现任务的同步,例如等待所有子任务完成后进行汇总。
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
int taskCount = 3;
CountDownLatch latch = new CountDownLatch(taskCount);
for (int i = 1; i <= taskCount; i++) {
int taskNumber = i;
new Thread(() -> {
System.out.println("任务 " + taskNumber + " 开始执行");
try {
Thread.sleep(1000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务 " + taskNumber + " 执行完成");
latch.countDown(); // 任务完成,计数器减1
}).start();
}
latch.await(); // 等待所有任务完成
System.out.println("所有任务执行完毕,主线程继续");
}
}
Callable 和 Future
用于获取线程执行的结果或捕获异常。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableExample {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
Callable<Integer> task = () -> {
System.out.println("任务开始执行");
Thread.sleep(1000);
return 42; // 返回结果
};
Future<Integer> future = threadPool.submit(task);
try {
System.out.println("任务结果:" + future.get()); // 获取任务执行结果
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
threadPool.shutdown();
}
}
实践操作:文件下载模拟
模拟多个文件下载任务,使用线程池执行任务,并使用 CountDownLatch
等待所有任务完成。
代码实现
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FileDownloadSimulation {
public static void main(String[] args) throws InterruptedException {
int fileCount = 5; // 文件总数
CountDownLatch latch = new CountDownLatch(fileCount);
ExecutorService threadPool = Executors.newFixedThreadPool(3); // 创建线程池
for (int i = 1; i <= fileCount; i++) {
int fileNumber = i;
threadPool.execute(() -> {
System.out.println("开始下载文件 " + fileNumber);
try {
Thread.sleep(2000); // 模拟下载耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("文件 " + fileNumber + " 下载完成");
latch.countDown(); // 下载完成后计数器减1
});
}
latch.await(); // 等待所有文件下载完成
System.out.println("所有文件下载完毕,主线程继续执行");
threadPool.shutdown(); // 关闭线程池
}
}
总结
- 线程池:线程池通过复用线程,避免频繁创建和销毁线程,提升性能并优化资源管理,适合高并发场景。
- CountDownLatch:用于等待多线程任务的完成,是同步任务执行的有效工具。
- Callable 和 Future:可以在线程池中获取任务结果或捕获异常,适用于需要结果返回的任务。
- 文件下载模拟:结合线程池和
CountDownLatch
,展示了多线程任务的同步和高效执行方法,在实际项目中应用广泛。