Java线程池及不同类型线程池的使用详解

概念

  • 线程池是一组预先创建的线程,用于执行任务。
  • 线程池可以重用线程,避免频繁地创建和销毁线程,提高性能和资源利用率。
  • 线程池可以根据需要调整线程数量,并提供任务调度和管理的功能。

四种线程池

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);
    }
}
Java线程池及不同类型线程池的使用详解

给TA打赏
共{{data.count}}人
人已打赏
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索