首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >字节跳动面试题:用过线程池吗?如何自定义线程池?线程池的参数?

字节跳动面试题:用过线程池吗?如何自定义线程池?线程池的参数?

作者头像
GeekLiHua
发布2025-01-21 15:11:10
发布2025-01-21 15:11:10
3250
举报
文章被收录于专栏:JavaJava

字节跳动面试题:用过线程池吗?如何自定义线程池?线程池的参数?

了解线程池

为什么要使用线程池?

使用线程池可以减少线程的创建和销毁次数,提高程序的性能和效率。它可以管理线程的数量、执行任务队列中的任务,并可配置各种参数以适应不同的应用场景。

Java中的线程池

Java提供了java.util.concurrent包来支持线程池的实现。

使用线程池

使用现有线程池

Java提供了Executors类来创建不同类型的线程池,比如FixedThreadPoolCachedThreadPool等。

示例代码:
代码语言:javascript
复制
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池,大小为5
        ExecutorService executor = Executors.newFixedThreadPool(5);

        // 循环提交任务到线程池
        for (int i = 0; i < 10; i++) {
            // 创建一个新的WorkerThread任务,并将其提交到线程池中执行
            Runnable worker = new WorkerThread("Task " + i);
            executor.execute(worker);
        }
        // 关闭线程池,不再接受新的任务
        executor.shutdown();

        // 等待所有线程执行完毕,即线程池中所有任务执行完毕
        while (!executor.isTerminated()) {
        }
        // 所有任务执行完毕后输出提示信息
        System.out.println("所有线程执行完毕");
    }

    // 定义一个实现了Runnable接口的WorkerThread类
    static class WorkerThread implements Runnable {
        private String task; // 任务描述信息

        // 构造函数,用于初始化任务描述信息
        public WorkerThread(String s) {
            this.task = s;
        }

        // 实现Runnable接口的run方法,执行具体的任务逻辑
        public void run() {
            // 输出当前线程名字、任务开始信息
            System.out.println(Thread.currentThread().getName() + " 开始执行任务:" + task);
            // 模拟任务执行,线程休眠2秒
            processCommand();
            // 输出当前线程名字、任务结束信息
            System.out.println(Thread.currentThread().getName() + " 任务执行完毕:" + task);
        }

        // 模拟任务执行的方法
        private void processCommand() {
            try {
                Thread.sleep(2000); // 休眠2秒,模拟任务执行耗时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 运行结果解释
代码语言:javascript
复制
pool-1-thread-2 开始执行任务:Task 1
pool-1-thread-5 开始执行任务:Task 4
pool-1-thread-4 开始执行任务:Task 3
pool-1-thread-3 开始执行任务:Task 2
pool-1-thread-1 开始执行任务:Task 0
pool-1-thread-2 任务执行完毕:Task 1
pool-1-thread-1 任务执行完毕:Task 0
pool-1-thread-1 开始执行任务:Task 6
pool-1-thread-5 任务执行完毕:Task 4
pool-1-thread-4 任务执行完毕:Task 3
pool-1-thread-4 开始执行任务:Task 8
pool-1-thread-3 任务执行完毕:Task 2
pool-1-thread-3 开始执行任务:Task 9
pool-1-thread-2 开始执行任务:Task 5
pool-1-thread-5 开始执行任务:Task 7
pool-1-thread-2 任务执行完毕:Task 5
pool-1-thread-3 任务执行完毕:Task 9
pool-1-thread-4 任务执行完毕:Task 8
pool-1-thread-5 任务执行完毕:Task 7
pool-1-thread-1 任务执行完毕:Task 6
所有线程执行完毕
  1. 任务分配和开始执行阶段:
    • 每个任务都被分配给线程池中的一个线程进行执行。
    • 根据输出,我们可以看到五个任务(Task 0 到 Task 4)被分配给了五个不同的线程(pool-1-thread-1 到 pool-1-thread-5)。
  2. 任务执行阶段:
    • 每个任务开始执行时,输出了一条消息,指示任务开始执行。
    • 任务的执行过程中,每个线程根据调度依次执行其任务。
    • 在这个阶段,线程池中的线程可能会动态地被重新分配给新的任务,以便更有效地利用系统资源。
  3. 任务执行完毕阶段:
    • 当任务执行完毕时,输出了一条消息,指示任务执行完毕。
    • 这些消息表明每个任务都顺利地完成了执行。
  4. 所有线程执行完毕阶段:
    • 最后,输出了一条消息,指示所有线程执行完毕。
    • 这表示所有任务都已经被执行完成,并且线程池中的所有线程都处于空闲状态。
自定义线程池

如果现有的线程池类型不能满足需求,可以自定义线程池。自定义线程池可以根据具体需求配置线程的核心数量、最大数量、任务队列等参数。

示例代码:
代码语言:javascript
复制
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CustomThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                4, // 最大线程数
                10, // 空闲线程存活时间
                TimeUnit.SECONDS, // 存活时间单位
                new LinkedBlockingQueue<Runnable>() // 无界任务队列
        );

        // 提交任务到线程池
        for (int i = 0; i < 6; i++) {
            Runnable worker = new WorkerThread("Task " + i, executor);
            executor.execute(worker);
        }

        // 关闭线程池
        executor.shutdown();

        // 等待所有线程执行完毕
        while (!executor.isTerminated()) {
            // 等待
        }

        // 输出所有线程执行完毕
        System.out.println("所有线程执行完毕");
    }

    // 定义一个实现了Runnable接口的WorkerThread类
    static class WorkerThread implements Runnable {
        private String task; // 任务描述信息
        private ThreadPoolExecutor executor; // 线程池

        // 构造函数,用于初始化任务描述信息和线程池
        public WorkerThread(String s, ThreadPoolExecutor executor) {
            this.task = s;
            this.executor = executor;
        }

        // 实现Runnable接口的run方法,执行具体的任务逻辑
        public void run() {
            // 获取当前线程名字
            String threadName = Thread.currentThread().getName();

            // 输出当前线程名字、任务开始信息
            System.out.println("线程 " + threadName + " 开始执行任务:" + task);

            // 获取当前线程池中的核心线程数
            int corePoolSize = executor.getCorePoolSize();

            // 判断当前线程是否为核心线程
            boolean isCoreThread = corePoolSize > 0;

            // 输出是否为核心线程信息
            System.out.println("线程 " + threadName + " 是否为核心线程:" + isCoreThread);

            // 模拟任务执行,线程休眠2秒
            processCommand();

            // 输出当前线程名字、任务结束信息
            System.out.println("线程 " + threadName + " 任务执行完毕:" + task);
        }

        // 模拟任务执行的方法
        private void processCommand() {
            try {
                Thread.sleep(2000); // 休眠2秒,模拟任务执行耗时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 运行结果
代码语言:javascript
复制
线程 pool-1-thread-2 开始执行任务:Task 1
线程 pool-1-thread-1 开始执行任务:Task 0
线程 pool-1-thread-2 是否为核心线程:true
线程 pool-1-thread-1 是否为核心线程:true
线程 pool-1-thread-1 任务执行完毕:Task 0
线程 pool-1-thread-2 任务执行完毕:Task 1
线程 pool-1-thread-2 开始执行任务:Task 3
线程 pool-1-thread-2 是否为核心线程:true
线程 pool-1-thread-1 开始执行任务:Task 2
线程 pool-1-thread-1 是否为核心线程:true
线程 pool-1-thread-1 任务执行完毕:Task 2
线程 pool-1-thread-1 开始执行任务:Task 4
线程 pool-1-thread-1 是否为核心线程:true
线程 pool-1-thread-2 任务执行完毕:Task 3
线程 pool-1-thread-2 开始执行任务:Task 5
线程 pool-1-thread-2 是否为核心线程:true
线程 pool-1-thread-1 任务执行完毕:Task 4
线程 pool-1-thread-2 任务执行完毕:Task 5
所有线程执行完毕

这个运行结果是一个线程池中的任务执行过程的输出。:

  • 线程 pool-1-thread-2 开始执行任务:Task 1: 线程池中的第二个线程开始执行任务 “Task 1”。
  • 线程 pool-1-thread-1 开始执行任务:Task 0: 线程池中的第一个线程开始执行任务 “Task 0”。
  • 线程 pool-1-thread-2 是否为核心线程:true: 线程池中的第二个线程是一个核心线程。
  • 线程 pool-1-thread-1 是否为核心线程:true: 线程池中的第一个线程是一个核心线程。
  • 线程 pool-1-thread-1 任务执行完毕:Task 0: 线程池中的第一个线程完成了任务 “Task 0”。
  • 线程 pool-1-thread-2 任务执行完毕:Task 1: 线程池中的第二个线程完成了任务 “Task 1”。
  • 线程 pool-1-thread-2 开始执行任务:Task 3: 第二个线程开始执行任务 “Task 3”。
  • 线程 pool-1-thread-2 是否为核心线程:true: 第二个线程仍然是一个核心线程。
  • 线程 pool-1-thread-1 开始执行任务:Task 2: 第一个线程开始执行任务 “Task 2”。
  • 线程 pool-1-thread-1 是否为核心线程:true: 第一个线程仍然是一个核心线程。
  • 线程 pool-1-thread-1 任务执行完毕:Task 2: 第一个线程完成了任务 “Task 2”。
  • 线程 pool-1-thread-1 开始执行任务:Task 4: 第一个线程开始执行任务 “Task 4”。
  • 线程 pool-1-thread-1 是否为核心线程:true: 第一个线程仍然是一个核心线程。
  • 线程 pool-1-thread-2 任务执行完毕:Task 3: 第二个线程完成了任务 “Task 3”。
  • 线程 pool-1-thread-2 开始执行任务:Task 5: 第二个线程开始执行任务 “Task 5”。
  • 线程 pool-1-thread-2 是否为核心线程:true: 第二个线程仍然是一个核心线程。
  • 线程 pool-1-thread-1 任务执行完毕:Task 4: 第一个线程完成了任务 “Task 4”。
  • 线程 pool-1-thread-2 任务执行完毕:Task 5: 第二个线程完成了任务 “Task 5”。
  • 所有线程执行完毕: 所有任务都被线程池中的线程执行完毕了。

自定义线程池参数详解
  1. 核心线程数(Core Pool Size):
    • 核心线程数是线程池中始终存活的线程数量。
    • 它负责执行任务队列中的任务,即使线程处于空闲状态,也不会被销毁。
代码语言:javascript
复制
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CoreThreadPoolExample {
    public static void main(String[] args) {
        // 设置核心线程数为2
        int corePoolSize = 2;

        // 创建一个线程池,指定核心线程数
        ExecutorService executor = Executors.newFixedThreadPool(corePoolSize);

        // 提交任务到线程池
        for (int i = 0; i < 5; i++) {
            Runnable worker = new WorkerThread("Task " + i);
            executor.execute(worker);
        }

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

    // 定义一个实现了Runnable接口的WorkerThread类
    static class WorkerThread implements Runnable {
        private String task; // 任务描述信息

        // 构造函数,用于初始化任务描述信息
        public WorkerThread(String s) {
            this.task = s;
        }

        // 实现Runnable接口的run方法,执行具体的任务逻辑
        public void run() {
            // 获取当前线程名字
            String threadName = Thread.currentThread().getName();

            // 输出当前线程名字、任务开始信息
            System.out.println("线程 " + threadName + " 开始执行任务:" + task);

            // 模拟任务执行,线程休眠2秒
            processCommand();

            // 输出当前线程名字、任务结束信息
            System.out.println("线程 " + threadName + " 任务执行完毕:" + task);
        }

        // 模拟任务执行的方法
        private void processCommand() {
            try {
                Thread.sleep(2000); // 休眠2秒,模拟任务执行耗时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 运行结果
代码语言:javascript
复制
线程 pool-1-thread-1 开始执行任务:Task 0
线程 pool-1-thread-2 开始执行任务:Task 1
线程 pool-1-thread-2 任务执行完毕:Task 1
线程 pool-1-thread-1 任务执行完毕:Task 0
线程 pool-1-thread-2 开始执行任务:Task 2
线程 pool-1-thread-1 开始执行任务:Task 3
线程 pool-1-thread-2 任务执行完毕:Task 2
线程 pool-1-thread-1 任务执行完毕:Task 3
线程 pool-1-thread-2 开始执行任务:Task 4
线程 pool-1-thread-2 任务执行完毕:Task 4
  1. 最大线程数(Maximum Pool Size):
    • 最大线程数是线程池中允许的最大线程数量。
    • 当任务队列已满且当前线程数小于最大线程数时,线程池会创建新的线程来执行任务。
代码语言:javascript
复制
import java.util.concurrent.*;

public class CustomThreadPoolExample {
    public static void main(String[] args) {
        int corePoolSize = 5; // 设置核心线程数
        int maxPoolSize = 10; // 设置最大线程数
        long keepAliveTime = 60; // 设置线程空闲时间
        TimeUnit unit = TimeUnit.SECONDS; // 设置空闲时间单位
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100); // 设置任务队列

        // 创建线程池
        ExecutorService executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue);

        // 提交任务到线程池
        for (int i = 0; i < 15; i++) {
            Runnable worker = new WorkerThread("Task " + i);
            executor.execute(worker);
        }

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

    // 定义一个实现了Runnable接口的WorkerThread类
    static class WorkerThread implements Runnable {
        private String task; // 任务描述信息

        // 构造函数,用于初始化任务描述信息
        public WorkerThread(String s) {
            this.task = s;
        }

        // 实现Runnable接口的run方法,执行具体的任务逻辑
        public void run() {
            // 获取当前线程名字
            String threadName = Thread.currentThread().getName();

            // 输出当前线程名字、任务开始信息
            System.out.println("线程 " + threadName + " 开始执行任务:" + task);

            // 模拟任务执行,线程休眠2秒
            processCommand();

            // 输出当前线程名字、任务结束信息
            System.out.println("线程 " + threadName + " 任务执行完毕:" + task);
        }

        // 模拟任务执行的方法
        private void processCommand() {
            try {
                Thread.sleep(2000); // 休眠2秒,模拟任务执行耗时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 空闲线程存活时间(Keep Alive Time):
    • 当线程池中的线程数量超过核心线程数时,空闲线程等待新任务的最长时间。
    • 超过这个时间后,空闲线程将被销毁,以节省系统资源。
代码语言:javascript
复制
import java.util.concurrent.*;

public class KeepAliveTimeExample {
    public static void main(String[] args) {
        int corePoolSize = 3; // 设置核心线程数
        int maxPoolSize = 5; // 设置最大线程数
        long keepAliveTime = 3; // 设置空闲线程存活时间(秒)
        TimeUnit unit = TimeUnit.SECONDS; // 设置空闲时间单位
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10); // 设置任务队列

        // 创建线程池,并设置空闲线程存活时间
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue);

        // 提交任务到线程池
        for (int i = 0; i < 10; i++) {
            Runnable worker = new WorkerThread("Task " + i);
            executor.execute(worker);
        }

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

    // 定义一个实现了Runnable接口的WorkerThread类
    static class WorkerThread implements Runnable {
        private String task; // 任务描述信息

        // 构造函数,用于初始化任务描述信息
        public WorkerThread(String s) {
            this.task = s;
        }

        // 实现Runnable接口的run方法,执行具体的任务逻辑
        public void run() {
            // 获取当前线程名字
            String threadName = Thread.currentThread().getName();

            // 输出当前线程名字、任务开始信息
            System.out.println("线程 " + threadName + " 开始执行任务:" + task);

            // 模拟任务执行,线程休眠2秒
            processCommand();

            // 输出当前线程名字、任务结束信息
            System.out.println("线程 " + threadName + " 任务执行完毕:" + task);
        }

        // 模拟任务执行的方法
        private void processCommand() {
            try {
                Thread.sleep(2000); // 休眠2秒,模拟任务执行耗时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 任务队列(Work Queue):
    • 任务队列用于保存等待执行的任务。
    • 不同类型的任务队列(如ArrayBlockingQueueLinkedBlockingQueue等)具有不同的特性,如有界性、无界性等。
    • ArrayBlockingQueue:有界队列,容量为10,当任务队列已满时,新的任务无法加入队列,需要等待队列中的任务被处理。
    • LinkedBlockingQueue:无界队列,可以无限制地添加任务,不会出现队列满的情况,但在高负载情况下可能会导致内存溢出。
代码语言:javascript
复制
import java.util.concurrent.*;

public class WorkQueueExample {
    public static void main(String[] args) {
        int corePoolSize = 3; // 设置核心线程数
        int maxPoolSize = 5; // 设置最大线程数
        long keepAliveTime = 3; // 设置空闲线程存活时间(秒)
        TimeUnit unit = TimeUnit.SECONDS; // 设置空闲时间单位

        // 使用有界队列(ArrayBlockingQueue)
        BlockingQueue<Runnable> arrayBlockingQueue = new ArrayBlockingQueue<>(10);
        ThreadPoolExecutor executorWithArrayBlockingQueue = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, unit, arrayBlockingQueue);

        // 使用无界队列(LinkedBlockingQueue)
        BlockingQueue<Runnable> linkedBlockingQueue = new LinkedBlockingQueue<>();
        ThreadPoolExecutor executorWithLinkedBlockingQueue = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, unit, linkedBlockingQueue);

        // 提交任务到线程池(使用有界队列)
        for (int i = 0; i < 10; i++) {
            Runnable worker = new WorkerThread("Task " + i);
            executorWithArrayBlockingQueue.execute(worker);
        }

        // 提交任务到线程池(使用无界队列)
        for (int i = 0; i < 10; i++) {
            Runnable worker = new WorkerThread("Task " + i);
            executorWithLinkedBlockingQueue.execute(worker);
        }

        // 关闭线程池(使用有界队列)
        executorWithArrayBlockingQueue.shutdown();

        // 关闭线程池(使用无界队列)
        executorWithLinkedBlockingQueue.shutdown();
    }

    // 定义一个实现了Runnable接口的WorkerThread类
    static class WorkerThread implements Runnable {
        private String task; // 任务描述信息

        // 构造函数,用于初始化任务描述信息
        public WorkerThread(String s) {
            this.task = s;
        }

        // 实现Runnable接口的run方法,执行具体的任务逻辑
        public void run() {
            // 获取当前线程名字
            String threadName = Thread.currentThread().getName();

            // 输出当前线程名字、任务开始信息
            System.out.println("线程 " + threadName + " 开始执行任务:" + task);

            // 模拟任务执行,线程休眠2秒
            processCommand();

            // 输出当前线程名字、任务结束信息
            System.out.println("线程 " + threadName + " 任务执行完毕:" + task);
        }

        // 模拟任务执行的方法
        private void processCommand() {
            try {
                Thread.sleep(2000); // 休眠2秒,模拟任务执行耗时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 拒绝策略(Rejected Execution Handler):
    • 当任务队列已满且线程池中的线程数量已达到最大线程数时,线程池无法执行新的任务时的处理策略。
    • 拒绝策略可以是抛出异常、丢弃任务、阻塞等。
    • AbortPolicy:默认的拒绝策略,当任务无法被执行时,会抛出 RejectedExecutionException 异常。 DiscardPolicy:丢弃策略,当任务无法被执行时,会默默地丢弃掉这个任务。 DiscardOldestPolicy:丢弃最旧策略,当任务无法被执行时,会移除最早进入任务队列的任务,然后尝试再次提交当前任务。 CallerRunsPolicy:调用者运行策略,当任务无法被执行时,会由提交任务的线程执行这个任务。
代码语言:javascript
复制
import java.util.concurrent.*;

public class RejectedExecutionHandlerExample {
    public static void main(String[] args) {
        int corePoolSize = 2; // 设置核心线程数
        int maxPoolSize = 3; // 设置最大线程数
        long keepAliveTime = 3; // 设置空闲线程存活时间(秒)
        TimeUnit unit = TimeUnit.SECONDS; // 设置空闲时间单位
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2); // 设置任务队列(有界队列)

        // 创建线程池,并设置空闲线程存活时间和拒绝策略
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue);

        // 设置四种不同的拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); // 中止策略
        //executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); // 丢弃策略
        //executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy()); // 丢弃最旧策略
        //executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 调用者运行策略

        // 提交任务到线程池
        for (int i = 0; i < 5; i++) {
            Runnable worker = new WorkerThread("Task " + i);
            executor.execute(worker);
        }

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

    // 定义一个实现了Runnable接口的WorkerThread类
    static class WorkerThread implements Runnable {
        private String task; // 任务描述信息

        // 构造函数,用于初始化任务描述信息
        public WorkerThread(String s) {
            this.task = s;
        }

        // 实现Runnable接口的run方法,执行具体的任务逻辑
        public void run() {
            // 获取当前线程名字
            String threadName = Thread.currentThread().getName();

            // 输出当前线程名字、任务开始信息
            System.out.println("线程 " + threadName + " 开始执行任务:" + task);

            // 模拟任务执行,线程休眠2秒
            processCommand();

            // 输出当前线程名字、任务结束信息
            System.out.println("线程 " + threadName + " 任务执行完毕:" + task);
        }

        // 模拟任务执行的方法
        private void processCommand() {
            try {
                Thread.sleep(2000); // 休眠2秒,模拟任务执行耗时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
线程池的应用场景
1. Web服务器
  • 在Web服务器中,经常需要处理大量的客户端请求。
  • 使用线程池可以有效地管理服务器资源,提高并发处理能力,保证服务器的稳定性和性能。
代码语言:javascript
复制
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class WebServer {
    private static final int MAX_THREADS = 100; // 最大线程数

    public static void main(String[] args) {
        // 创建一个固定大小的线程池,用于处理客户端请求
        ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);

        // 模拟客户端请求
        for (int i = 0; i < 20; i++) {
            // 创建客户端请求任务并提交给线程池执行
            executor.execute(new ClientRequest("Request " + i));
        }

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

    // 定义一个模拟客户端请求的任务类
    static class ClientRequest implements Runnable {
        private String request;

        // 构造函数,初始化客户端请求信息
        public ClientRequest(String request) {
            this.request = request;
        }

        @Override
        public void run() {
            // 模拟处理客户端请求的业务逻辑
            processRequest();
        }

        // 模拟处理客户端请求的业务逻辑
        private void processRequest() {
            // 输出开始处理请求的信息
            System.out.println("开始处理客户端请求:" + request);

            try {
                // 模拟处理请求的耗时操作
                Thread.sleep(1000);

                // 输出请求处理完成的信息
                System.out.println("请求处理完成:" + request);
            } catch (InterruptedException e) {
                // 输出请求处理被中断的信息
                System.out.println("请求处理被中断:" + request);
            }
        }
    }
}
代码语言:javascript
复制
开始处理客户端请求:Request 0
开始处理客户端请求:Request 2
开始处理客户端请求:Request 1
开始处理客户端请求:Request 3
开始处理客户端请求:Request 4
开始处理客户端请求:Request 5
开始处理客户端请求:Request 6
开始处理客户端请求:Request 7
开始处理客户端请求:Request 8
开始处理客户端请求:Request 9
开始处理客户端请求:Request 10
开始处理客户端请求:Request 12
开始处理客户端请求:Request 11
开始处理客户端请求:Request 13
开始处理客户端请求:Request 14
开始处理客户端请求:Request 15
开始处理客户端请求:Request 16
开始处理客户端请求:Request 18
开始处理客户端请求:Request 19
开始处理客户端请求:Request 17
请求处理完成:Request 13
请求处理完成:Request 0
请求处理完成:Request 8
请求处理完成:Request 7
请求处理完成:Request 16
请求处理完成:Request 6
请求处理完成:Request 14
请求处理完成:Request 5
请求处理完成:Request 3
请求处理完成:Request 15
请求处理完成:Request 4
请求处理完成:Request 19
请求处理完成:Request 2
请求处理完成:Request 1
请求处理完成:Request 12
请求处理完成:Request 11
请求处理完成:Request 10
请求处理完成:Request 9
请求处理完成:Request 18
请求处理完成:Request 17
2. 数据库连接池
  • 数据库连接是一种宝贵的资源,频繁地创建和销毁连接会导致系统性能下降。
  • 使用线程池管理数据库连接可以避免资源的频繁分配和释放,提高数据库访问的效率。
代码语言:javascript
复制
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class DatabaseConnectionPool {
    private static final String DB_URL = "jdbc:mysql://localhost:3306/mydatabase";
    private static final String DB_USER = "username";
    private static final String DB_PASSWORD = "password";

    private static final int POOL_SIZE = 10; // 连接池大小

    private BlockingQueue<Connection> connectionPool; // 连接池
    private ExecutorService executorService; // 线程池

    public DatabaseConnectionPool() {
        // 初始化连接池
        connectionPool = new ArrayBlockingQueue<>(POOL_SIZE);
        // 初始化线程池
        executorService = Executors.newCachedThreadPool();

        // 初始化连接池中的连接
        for (int i = 0; i < POOL_SIZE; i++) {
            try {
                Connection connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
                connectionPool.put(connection);
            } catch (SQLException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // 从连接池中获取连接
    public Connection getConnection() throws InterruptedException {
        return connectionPool.take();
    }

    // 将连接放回连接池
    public void releaseConnection(Connection connection) throws InterruptedException {
        if (connection != null) {
            connectionPool.put(connection);
        }
    }

    // 关闭连接池
    public void closePool() {
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
        }
        connectionPool.forEach(connection -> {
            try {
                if (connection != null && !connection.isClosed()) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        });
    }
}

在这个数据库连接池的示例中,采用了基于阻塞队列的方式来实现连接池的管理,以及使用线程池来处理数据库连接的请求。

  • 连接池的初始化: 在构造函数中,创建了一个固定大小的阻塞队列作为连接池,并使用 JDBC 连接来填充这个连接池。
  • 获取连接和释放连接: getConnection() 方法用于从连接池中获取连接,releaseConnection() 方法用于将连接放回连接池。
  • 关闭连接池: closePool() 方法用于关闭连接池,在关闭之前会确保连接池中的所有连接都被正确地关闭。
3. 图像处理
  • 在图像处理应用中,通常需要处理大量的图片文件。
  • 使用线程池可以并发地处理多张图片,加快处理速度,提高用户体验。
代码语言:javascript
复制
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ImageProcessor {
    private static final String IMAGE_DIRECTORY = "/path/to/image/directory";
    private static final int THREAD_POOL_SIZE = 5;

    public static void main(String[] args) {
        // 创建固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);

        // 获取图像文件列表
        File imageDirectory = new File(IMAGE_DIRECTORY);
        File[] imageFiles = imageDirectory.listFiles();

        // 处理每张图片
        if (imageFiles != null) {
            for (File imageFile : imageFiles) {
                // 提交任务给线程池处理
                executor.submit(new ImageTask(imageFile));
            }
        }

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

    // 图像处理任务类
    static class ImageTask implements Runnable {
        private File imageFile;

        public ImageTask(File imageFile) {
            this.imageFile = imageFile;
        }

        @Override
        public void run() {
            // 执行图像处理逻辑
            processImage(imageFile);
        }

        // 图像处理逻辑
        private void processImage(File imageFile) {
            System.out.println("处理图像文件:" + imageFile.getName());
            // 在这里编写具体的图像处理逻辑
            // 例如,缩放、裁剪、滤镜等操作
        }
    }
}

这个示例演示了如何使用线程池处理图像文件。主要步骤包括:

  1. 创建线程池: 使用 Executors.newFixedThreadPool() 方法创建一个固定大小的线程池,指定了线程池的大小为 5。
  2. 获取图像文件列表: 从指定的图像目录中获取图像文件列表。
  3. 提交任务给线程池: 遍历图像文件列表,为每个图像文件创建一个 ImageTask 任务,并将其提交给线程池执行。
  4. 图像处理逻辑: ImageTask 类实现了 Runnable 接口,其中的 run() 方法定义了图像处理的逻辑。在 processImage() 方法中,可以编写具体的图像处理逻辑,例如图像缩放、裁剪、添加滤镜等操作。
  5. 关闭线程池: 在任务执行完毕后,调用线程池的 shutdown() 方法关闭线程池。
4. 文件上传下载
  • 文件上传下载是Web应用中常见的功能之一。
  • 使用线程池可以并发处理多个上传下载任务,提高文件传输效率,缩短用户等待时间。
代码语言:javascript
复制
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FileTransferManager {
    private static final String UPLOAD_DIRECTORY = "/path/to/upload/directory";
    private static final int THREAD_POOL_SIZE = 5;

    public static void main(String[] args) {
        // 创建固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);

        // 获取上传目录中的文件列表
        File uploadDirectory = new File(UPLOAD_DIRECTORY);
        File[] files = uploadDirectory.listFiles();

        // 处理每个文件(模拟上传下载任务)
        if (files != null) {
            for (File file : files) {
                // 提交上传下载任务给线程池处理
                executor.submit(new FileTransferTask(file));
            }
        }

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

    // 文件传输任务类
    static class FileTransferTask implements Runnable {
        private File file;

        public FileTransferTask(File file) {
            this.file = file;
        }

        @Override
        public void run() {
            // 执行文件上传下载逻辑
            transferFile(file);
        }

        // 文件上传下载逻辑
        private void transferFile(File file) {
            System.out.println("处理文件:" + file.getName());
            // 在这里编写具体的文件上传下载逻辑
            // 例如,将文件上传到远程服务器,或者从远程服务器下载文件等操作
        }
    }
}

这个示例展示了如何使用线程池处理文件上传下载任务。主要步骤如下:

  1. 创建线程池: 使用 Executors.newFixedThreadPool() 方法创建一个固定大小的线程池,指定了线程池的大小为 5。
  2. 获取上传目录中的文件列表: 从指定的上传目录中获取文件列表。
  3. 提交任务给线程池: 遍历文件列表,为每个文件创建一个 FileTransferTask 任务,并将其提交给线程池执行。
  4. 文件上传下载逻辑: FileTransferTask 类实现了 Runnable 接口,其中的 run() 方法定义了文件上传下载的逻辑。在 transferFile() 方法中,可以编写具体的文件上传下载逻辑,例如将文件上传到远程服务器,或者从远程服务器下载文件等操作。
  5. 关闭线程池: 在任务执行完毕后,调用线程池的 shutdown() 方法关闭线程池。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 字节跳动面试题:用过线程池吗?如何自定义线程池?线程池的参数?
    • 了解线程池
      • 为什么要使用线程池?
      • Java中的线程池
    • 使用线程池
      • 使用现有线程池
      • 自定义线程池
      • 自定义线程池参数详解
      • 线程池的应用场景
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档