原创

java面试题-Executors线程池你了解多少?

1. Executors 概述

在 Java 中,线程池的顶级接口是 Executor,但是严格意义上讲,Executor 并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是 ExecutorServiceThreadPoolExecutorExecutors 类的底层实现。让我们先来详细了解 Executors

1.1 Executors 源码解析

Executors 类提供了一些静态方法来创建不同类型的线程池。其中,最常用的方法之一是 newFixedThreadPool,用于创建一个固定大小的线程池。以下是对 Executors 类的源码解析:

public class Executors {

    // 创建一个固定大小的线程池
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    // 其他静态方法省略...
}

在上述代码中,newFixedThreadPool 方法返回一个新的固定大小的线程池。该线程池使用 ThreadPoolExecutor 类的构造函数进行初始化,指定了核心线程数、最大线程数、线程空闲时间、时间单位和阻塞队列。

1.2 线程池的基本思想

线程池的基本思想是一种对象池的思想。它开辟一块内存空间,里面存放了众多(未死亡)的线程。线程池由池管理器进行管理,池中线程的执行调度由池管理器处理。当有线程任务时,线程池从池中取一个线程执行任务,执行完成后线程对象归池。这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。

2. Executors 示例代码解析

下面是一个示例代码,演示了如何使用 Executors 类中的 newFixedThreadPool 方法创建一个固定大小的线程池,并提交任务给线程池执行。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorsExample {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池,包含5个工作线程
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        // 提交任务给线程池执行
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executorService.execute(() -> {
                System.out.println("Task " + taskId + " is executing by " + Thread.currentThread().getName());
                // 模拟任务执行
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        // 关闭线程池
        executorService.shutdown();
    }
}

在上述代码中,通过 Executors.newFixedThreadPool(5) 创建一个固定大小为5的线程池,并提交10个任务给线程池执行。每个任务的执行模拟耗时操作,通过观察输出可以看到线程池的工作原理。

3. Executors 源码解析

3.1 Executors

Executors 类提供了一系列工厂方法,用于创建不同类型的线程池。下面对其中一个常用方法 newFixedThreadPool 进行源码解析。

public class Executors {

    // 创建一个固定大小的线程池
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    // 其他静态方法省略...
}

在上述代码中,newFixedThreadPool 方法返回一个 ThreadPoolExecutor 实例,它是 ExecutorService 的实现类。通过传入参数,确定线程池的核心线程数、最大线程数、线程空闲时间、时间单位和阻塞队列。

3.2 ThreadPoolExecutor

ThreadPoolExecutor 是线程池的底层实现类。下面是 ThreadPoolExecutor 的关键源码片段解析:

public class ThreadPoolExecutor extends AbstractExecutorService {

    // 构造方法
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        // 构造方法实现省略...
    }

    // execute 方法,用于提交任务给线程池执行
    public void execute(Runnable command) {
        // execute 方法实现省略...
    }

    // 其他方法省略...
}

在上述代码中,通过构造方法传入的参数初始化了线程池的核心线程数、最大线程数、线程空闲时间、时间单位和阻塞队列。而 execute 方法用于提交任务给线程池执行。

4. 总结

通过深入解析 Executors 源码和线程池的基本思想,我们更全面地理解了线程池的实现原理。Executors 提供了便捷的工厂方法,而线程池的核心思想是通过对象池来提高线程的利用率,减少系统资源的开销。

正文到此结束
本文目录