ToB企服应用市场:ToB评测及商务社交产业平台

标题: Java线程池使用浅谈 [打印本页]

作者: 去皮卡多    时间: 2024-2-26 15:42
标题: Java线程池使用浅谈
1. 线程池相关基本概念

线程池的设计目的是提高系统的性能和资源利用率。通过重用线程和控制并发线程的数量,线程池可以减少线程创建和销毁的开销,避免资源耗尽,并提供更好的任务调度和执行控制。
在使用线程池时,我们可以根据任务的类型和系统的需求来选择适当的线程池大小、拒绝策略和其他参数,以实现最佳的性能和可扩展性。
2. 线程池主要处理流程


更进一步的里层核心类处理流程:
当我们使用 Java 中的 ThreadPoolExecutor 类来创建线程池时,其处理流程如下:
ThreadPoolExecutor 是 Java 中用于创建和管理线程池的核心类,通过其灵活的配置参数,可以实现对线程池的各种行为和特性进行定制。这个类提供了丰富的方法和选项,用于控制线程池的大小、任务队列类型、拒绝策略、线程工厂等,以满足不同场景下的需求。
3. 线程池实现的主要步骤

3.1 创建线程池

在 Java 中,可以使用 Executors 类提供的静态方法创建线程池。以下是几种常见的创建线程池的方法:
3.1.1 创建固定大小的线程池

固定大小的线程池将在初始化时创建指定数量的线程,并且不会增加或减少线程的数量。
  1. ExecutorService executorService = Executors.newFixedThreadPool(10);//创建一个固定大小为 10 的线程池
复制代码
3.1.2 创建单个线程的线程池

单个线程的线程池只会创建一个工作线程来执行任务。
  1. ExecutorService executorService = Executors.newSingleThreadExecutor();
复制代码
3.1.3 创建可根据需要自动调整大小的线程池

可根据需要自动调整大小的线程池将根据任务的数量动态地增加或减少线程的数量。
  1. ExecutorService executorService = Executors.newCachedThreadPool();
复制代码
3.1.4 手动按自己需求创建线程池

在 Java 中,可以手动创建线程池,而不仅仅依赖于内置的线程池实现。手动创建线程池的主要原因是为了更好地控制线程池的行为、特性和参数配置,以满足特定的需求,比如特定的任务队列类型需求,特定的拒绝策略需求
根据ThreadPoolExecutor构造方法可知,需要准备以下参数:
  1. import java.util.concurrent.*;
  2. // 自定义拒绝策略类
  3. class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
  4.     @Override
  5.     public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
  6.         // 自定义拒绝策略的逻辑
  7.         System.out.println("Task Rejected: " + runnable.toString());
  8.         // 可根据需求进行不同的处理方式,如抛出异常、丢弃任务、调用者执行等
  9.     }
  10. }
  11. // 自定义线程工厂类
  12. class CustomThreadFactory implements ThreadFactory {
  13.     @Override
  14.     public Thread newThread(Runnable runnable) {
  15.         // 自定义线程工厂的逻辑
  16.         Thread thread = new Thread(runnable);
  17.         // 可以进行一些线程属性的配置,如设置线程名称、优先级等
  18.         thread.setName("CustomThread");
  19.         thread.setPriority(Thread.NORM_PRIORITY);
  20.         return thread;
  21.     }
  22. }
  23. public class ManualThreadPoolCreationExample {
  24.     public static void main(String[] args) {
  25.         // 创建自定义的拒绝策略实例
  26.         RejectedExecutionHandler rejectionHandler = new CustomRejectedExecutionHandler();
  27.         // 创建自定义的线程工厂实例
  28.         ThreadFactory threadFactory = new CustomThreadFactory();
  29.         // 创建任务队列(这里使用无界队列)
  30.         BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
  31.         // 创建线程池并进行手动配置
  32.         int corePoolSize = 10;
  33.         int maxPoolSize = 20;
  34.         long keepAliveTime = 60;
  35.         TimeUnit timeUnit = TimeUnit.SECONDS;
  36.         ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
  37.                 corePoolSize,
  38.                 maxPoolSize,
  39.                 keepAliveTime,
  40.                 timeUnit,
  41.                 workQueue,
  42.                 threadFactory,
  43.                 rejectionHandler
  44.         );
  45.     }
  46. }
复制代码
3.2 提交任务给线程池执行

创建线程池之后,可以将任务提交给线程池执行。任务可以是实现了 Runnable 接口的对象,也可以是实现了 Callable 接口的对象。
3.2.1  提交 Runnable 任务
  1. executorService.execute(new Runnable() {
  2.     @Override
  3.     public void run() {
  4.         // 任务逻辑
  5.     }
  6. });
  7. 或者使用 Lambda 表达式:
  8. executorService.execute(() -> {
  9.     // 任务逻辑
  10. });
复制代码
3.2.2 提交 Callable 任务
Callable 任务可以返回一个结果
  1. Future<SomeResult> future = executorService.submit(new Callable<SomeResult>() {
  2.     @Override
  3.     public SomeResult call() throws Exception {
  4.         // 任务逻辑
  5.         return someResult;
  6.     }
  7. });
  8. 或者使用 Lambda 表达式:
  9. Future<SomeResult> future = executorService.submit(() -> {
  10.     // 任务逻辑
  11.     return someResult;
  12. });
复制代码
3.3 关闭线程池

当不再需要线程池时,应该显式地关闭它,以释放资源。关闭线程池两种方式
  1. executorService.shutdown(); // 不再接受新的任务,但会等待已提交的任务执行完成。
  2. executorService.shutdownNow(); //希望立即关闭线程池,并尝试中断正在执行的任务
复制代码
3.4 处理任务执行结果

当提交任务给线程池执行后,可以通过 Future 对象来获取任务的执行结果。
  1. Future<SomeResult> future = executorService.submit(...);
  2. try {
  3.     SomeResult result = future.get();
  4.     // 处理结果
  5. } catch (InterruptedException e) {
  6.     // 处理中断异常
  7. } catch (ExecutionException e) {
  8.     // 处理执行异常
  9. }
复制代码
使用 future.get() 方法可以阻塞当前线程,直到任务执行完成并返回结果。get() 方法可能会抛出 InterruptedException 和 ExecutionException 异常,需要进行适当的异常处理。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4