Java线程池及不同类型线程池的使用详解
共计 3147 个字符,预计需要花费 8 分钟才能阅读完成。
概念
-
线程池是一组预先创建的线程,用于执行任务。
-
线程池可以重用线程,避免频繁地创建和销毁线程,提高性能和资源利用率。
-
线程池可以根据需要调整线程数量,并提供任务调度和管理的功能。
四种线程池
1. 固定大小线程池
创建方式:Executors.newFixedThreadPool()
线程池中的线程数量是固定的,任务会被放入任务队列等待执行。当有新任务提交时,如果有空闲线程可用,立即执行任务;否则,任务会等待直到有空闲线程为止。
2. 缓存线程池
创建方式:Executors.newCachedThreadPool()
缓存线程池中的线程数量是动态变化的,根据任务的数量自动调整。如果有空闲线程可用,任务会立即分配给空闲线程执行;否则,会创建新的线程来执行任务。
3. 单线程线程池
创建方式:Executors.newSingleThreadExecutor()
单线程线程池中只有一个线程在执行任务,保证任务的顺序性。所有提交的任务按顺序执行,适用于需要顺序执行任务的场景。
4. 定时任务线程池
创建方式:Executors.newScheduledThreadPool()
定时任务线程池可以执行定时任务和周期性任务。除了执行普通任务外,还可以执行延迟任务和周期性任务。
测试方法
以下是几种线程池的测试方法。
public class ThreadPoolTest {
/**
* 当有新任务提交时,如果线程池中有空闲线程,则立即执行;如果没有空闲线程,则任务会被放入任务队列等待执行,直到有空闲线程为止。
* 结果:线程基本是2个2个一起执行的,打印基本是两行一起
*/
@Test
public void test1() throws InterruptedException {
// 固定大小线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
System.out.println("实际创建的线程池对象:" + fixedThreadPool);
submitTasks(fixedThreadPool, "固定大小线程池");
Thread.sleep(6000);
fixedThreadPool.shutdown();
}
/**
* 有任务提交给缓存线程池时,如果有空闲线程可用,那么任务将被立即分配给一个空闲线程执行。如果没有空闲线程可用,缓存线程池会创建一个新的线程来执行任务。
* 结果:基本是一次性执行完毕
*/
@Test
public void test2() throws InterruptedException {
// 缓存线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
submitTasks(cachedThreadPool, "缓存线程池");
Thread.sleep(3000);
cachedThreadPool.shutdown();
}
/**
* 创建一个单线程的线程池,该线程池中只有一个线程在执行任务。所有提交的任务按顺序执行,保证任务的顺序性。
* 结果:线程一个个执行,控制台一行行打印
*/
@Test
public void test3() throws InterruptedException {
// 单线程线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
submitTasks(singleThreadExecutor, "单线程线程池");
Thread.sleep(12000);
singleThreadExecutor.shutdown();
}
/**
* 创建一个定时任务线程池,可以用于执行定时任务和周期性任务。除了可以执行普通任务外,该线程池还可以执行延迟任务和周期性任务。
* 结果:每2秒打印一次
*/
@Test
public void test4() throws InterruptedException {
// 创建定时任务线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
System.out.println("实际创建的线程池对象:" + scheduledThreadPool);
scheduleTasks(scheduledThreadPool, "定时任务线程池");
Thread.sleep(10000);
scheduledThreadPool.shutdown();
}
/**
* execute 用于执行没有返回的线程 - 参数为 Runnable 对象,返回值为 void
* submit 用于执行有返回结果的线程 - 参数为 Runnable 对象,返回值 Future 对象
*/
@Test
public void test5() throws ExecutionException, InterruptedException {
// 创建 ExecutorService
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 线程1,仅打印,无返回值
executorService.execute(() -> {
for(int i=0; i<5; i++){
System.out.println("无返回值线程第" + (i+1) + "次执行....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Future<Integer> future = executorService.submit(() -> {
// 任务的执行逻辑
Thread.sleep(3000);
System.out.println("有返回值线程执行完成...");
return 42;
});
System.out.println(future.get());
Thread.sleep(12000);
}
private static void submitTasks(ExecutorService executor, String poolName) {
System.out.println("===========" + poolName + "开始执行任务==========");
for (int i = 1; i <= 10; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println(poolName + "执行任务" + taskId);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
private static void scheduleTasks(ScheduledExecutorService executor, String poolName) {
System.out.println("===========" + poolName + "开始执行定时任务==========");
ScheduledFuture<?> scheduledFuture = executor.scheduleAtFixedRate(() -> {
System.out.println(poolName + "执行定时任务,时间:" + new Date());
}, 0, 2, TimeUnit.SECONDS);
System.out.println(scheduledFuture);
}
}
提醒:本文发布于238天前,文中所关联的信息可能已发生改变,请知悉!
Tips:清朝云网络工作室
阅读剩余
THE END