首页 > 编程语言 >Java面试要点98 - Java中线程池的任务提交过程

Java面试要点98 - Java中线程池的任务提交过程

时间:2024-12-26 10:29:27浏览次数:6  
标签:程池 Java System 98 任务 Task new public ThreadPoolExecutor

在这里插入图片描述

文章目录


引言

在Java并发编程中,了解线程池的任务提交过程对于正确使用线程池至关重要。本文将详细介绍任务从提交到执行的完整流程,包括任务提交方式、执行流程以及相关的异常处理机制。

一、任务提交方式

1.1 execute方法

execute方法是ThreadPoolExecutor提供的最基本的任务提交方式,用于提交不需要返回值的任务。它只接受Runnable类型的任务,不会返回任务的执行结果。

public class ExecuteExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2, 4,
            60L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2)
        );
        
        executor.execute(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("Task executed by " + 
                    Thread.currentThread().getName());
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
    }
}

1.2 submit方法

submit方法是通过ExecutorService接口提供的任务提交方式,可以提交有返回值的任务。它接受Callable或Runnable类型的任务,并返回Future对象。

public class SubmitExample {
    public static void main(String[] args) throws Exception {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2, 4,
            60L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2)
        );
        
        // 提交Callable任务
        Future<String> future = executor.submit(() -> {
            Thread.sleep(1000);
            return "Task result";
        });
        
        // 获取任务结果
        String result = future.get();
        System.out.println("Task result: " + result);
    }
}

二、任务执行流程

2.1 核心流程分析

当任务提交到线程池后,线程池会根据当前的运行状态和配置来决定如何处理任务。一般会经过以下判断流程:核心线程数判断、任务队列判断、最大线程数判断。

public class TaskExecutionFlow {
    private ThreadPoolExecutor createThreadPool() {
        return new ThreadPoolExecutor(
            2, // 核心线程数
            4, // 最大线程数
            60L, TimeUnit.SECONDS, // 线程存活时间
            new ArrayBlockingQueue<>(2), // 任务队列
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );
    }
    
    public void demonstrateExecutionFlow() {
        ThreadPoolExecutor executor = createThreadPool();
        
        // 提交多个任务演示执行流程
        for (int i = 0; i < 6; i++) {
            final int taskId = i;
            try {
                executor.execute(() -> {
                    System.out.printf("Task %d is running on %s%n",
                        taskId, Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                });
            } catch (RejectedExecutionException e) {
                System.out.println("Task " + taskId + " was rejected");
            }
        }
    }
}

2.2 任务状态转换

任务在提交到执行的过程中会经历多个状态:等待执行、正在执行、执行完成或异常终止。通过Future可以监控任务的执行状态。

public class TaskStateMonitor {
    public static void monitorTaskState() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, 1, 0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>()
        );
        
        Future<String> future = executor.submit(() -> {
            System.out.println("Task started");
            Thread.sleep(2000);
            return "Task completed";
        });
        
        // 监控任务状态
        while (!future.isDone()) {
            System.out.println("Task is still running...");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        
        try {
            String result = future.get();
            System.out.println("Final result: " + result);
        } catch (Exception e) {
            System.out.println("Task execution failed: " + e.getMessage());
        }
    }
}

三、任务队列处理

3.1 队列类型选择

不同的队列类型会影响任务的提交和执行方式。常用的队列类型包括ArrayBlockingQueue、LinkedBlockingQueue和SynchronousQueue。

public class QueueTypeDemo {
    // 有界队列示例
    public ThreadPoolExecutor createWithArrayQueue() {
        return new ThreadPoolExecutor(
            2, 4, 60L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(100)
        );
    }
    
    // 无界队列示例
    public ThreadPoolExecutor createWithLinkedQueue() {
        return new ThreadPoolExecutor(
            2, 4, 60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>()
        );
    }
    
    // 同步队列示例
    public ThreadPoolExecutor createWithSynchronousQueue() {
        return new ThreadPoolExecutor(
            2, 4, 60L, TimeUnit.SECONDS,
            new SynchronousQueue<>()
        );
    }
}

3.2 队列满时的处理

当任务队列满时,线程池会根据配置的拒绝策略来处理新提交的任务。可以实现自定义的拒绝策略来满足特定需求。

public class QueueFullHandling {
    public static class LoggingRejectedHandler 
            implements RejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r, 
                ThreadPoolExecutor executor) {
            System.out.println("Task rejected at: " + 
                System.currentTimeMillis());
            System.out.println("Current pool size: " + 
                executor.getPoolSize());
            System.out.println("Queue size: " + 
                executor.getQueue().size());
            
            // 可以将任务信息保存到日志或数据库
            saveRejectedTask(r);
        }
        
        private void saveRejectedTask(Runnable task) {
            // 保存任务信息的具体实现
        }
    }
    
    public static void demonstrateRejection() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, 2,
            60L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1),
            new LoggingRejectedHandler()
        );
        
        // 提交超过线程池处理能力的任务
        for (int i = 0; i < 4; i++) {
            final int taskId = i;
            executor.execute(() -> {
                try {
                    Thread.sleep(1000);
                    System.out.println("Task " + taskId + " executed");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
    }
}

四、异常处理

4.1 提交时异常处理

在任务提交过程中可能出现的异常包括RejectedExecutionException等,需要妥善处理这些异常。

public class ExceptionHandling {
    public void submitTaskWithExceptionHandling() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            1, 1,
            0L, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(1)
        );
        
        try {
            executor.execute(() -> {
                // 任务逻辑
                System.out.println("Task executed");
            });
        } catch (RejectedExecutionException e) {
            // 处理任务拒绝异常
            System.out.println("Task rejected: " + e.getMessage());
            // 可以选择重试或其他处理方式
            handleRejectedTask();
        } catch (Exception e) {
            // 处理其他可能的异常
            System.out.println("Task submission failed: " + e.getMessage());
        }
    }
    
    private void handleRejectedTask() {
        // 实现任务拒绝后的处理逻辑
    }
}

4.2 执行时异常处理

任务执行过程中的异常需要通过定制线程池或使用Future来捕获和处理。

public class ExecutionExceptionHandling {
    public static class CustomThreadPool extends ThreadPoolExecutor {
        public CustomThreadPool(int corePoolSize, int maximumPoolSize,
                long keepAliveTime, TimeUnit unit,
                BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, 
                  unit, workQueue);
        }
        
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            if (t != null) {
                System.out.println("Task failed with exception: " + 
                    t.getMessage());
                // 记录异常信息
                logException(t);
            }
        }
        
        private void logException(Throwable t) {
            // 实现异常日志记录
        }
    }
    
    public void demonstrateExceptionHandling() {
        CustomThreadPool executor = new CustomThreadPool(
            2, 4, 60L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2)
        );
        
        Future<?> future = executor.submit(() -> {
            throw new RuntimeException("Task failed");
        });
        
        try {
            future.get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            System.out.println("Task execution failed: " + 
                e.getCause().getMessage());
        }
    }
}

总结

线程池的任务提交是一个复杂的过程,涉及多个环节和多种情况的处理。通过合理使用不同的提交方式、选择适当的队列类型、实现完善的异常处理机制,可以确保任务能够被正确且高效地处理。在实际应用中,要根据具体场景选择合适的配置,并做好异常处理和监控。

标签:程池,Java,System,98,任务,Task,new,public,ThreadPoolExecutor
From: https://blog.csdn.net/weixin_55344375/article/details/144667548

相关文章

  • Java面试要点97 - Java中ThreadPoolExecutor源码解析
    文章目录引言一、核心属性1.1状态与线程数量的原子控制1.2任务队列与工作线程组二、Worker线程包装类2.1Worker类的设计三、任务提交源码分析3.1execute方法实现3.2addWorker核心方法四、任务执行源码分析4.1runWorker方法实现4.2getTask方法分析五、线程池......
  • 【最新原创毕设】基于PPH的花涧订购系统+00332(免费领源码)可做计算机毕业设计JAVA、PHP
    摘 要近年来,电子商务的快速发展引起了行业和学术界的高度关注。花涧订购系统旨在为用户提供一个简单、高效、便捷的花卉购物体验,它不仅要求用户清晰地查看所需信息,而且还要求界面设计精美,使得功能与页面完美融合,从而提升系统的可操作性。因此,我们需要深入研究信息内容,并利用......
  • JavaScript中的数组和函数在内存分别是如何存储的?
    在JavaScript中,数组和函数在内存中的存储方式涉及到JavaScript的内存管理机制,特别是堆(Heap)和栈(Stack)的使用。虽然这些概念在底层实现上可能因JavaScript引擎(如V8,SpiderMonkey等)的不同而有所差异,但我们可以从一个高层次的视角来理解它们。1.数组在内存中的存储数组在JavaScript......
  • JavaScript的对象属性描述符有哪些?分别有什么作用?
    在JavaScript中,对象的属性描述符主要分为两类:数据描述符和存取描述符。它们都具有以下属性:数据描述符:具有值的属性,该值可能是可写的,也可能不是。数据描述符具有以下属性:value:属性的值。默认是undefined。writable:当且仅当属性的值可能改变时为true。默认是false。enumer......
  • java基础3
    异常Java异常类层次结构图概览:Exception和Error有什么区别?在Java中,所有的异常都有一个共同的祖先java.lang包中的Throwable类。Throwable类有两个重要的子类:Exception:程序本身可以处理的异常,可以通过catch来进行捕获。Exception又可以分为CheckedExcept......
  • JVM实战—1.Java代码的运行原理
    大纲1.Java代码到底是如何运行起来的2.JVM类加载机制的一系列概念3.JVM中有哪些内存区域及各自的作用4.JVM的垃圾回收机制的作用5.问题汇总1.Java代码到底是如何运行起来的(1)首先假设写好了一个Java系统(2)把.java代码文件编译成.class字节码文件(3)启动JVM进程运行......
  • JVM实战—1.Java代码的运行原理
    大纲1.Java代码到底是如何运行起来的2.JVM类加载机制的一系列概念3.JVM中有哪些内存区域及各自的作用4.JVM的垃圾回收机制的作用5.问题汇总 1.Java代码到底是如何运行起来的(1)首先假设写好了一个Java系统(2)把.java代码文件编译成.class字节码文件(3)启动JVM进程运行.......
  • 基于Java+SpringBoot的预报名管理系统
    关注底部领取源码源码编号:S399源码名称:基于SpringBoot的预报名管理系统用户类型:双角色,用户、管理员主要技术:Java、Vue、ElementUl、SpringBoot运行环境:Windows/Mac、JDK1.8及以上运行工具:IDEA/Eclipse数 据 库:MySQL5.7及以上版本数据库表数量:14张表是否有毕业论......
  • 基于Java+SpringBoot的面向智慧教育的实习实践系统
    关注底部领取源码源码编号:S401源码名称:基于SpringBoot的面向智慧教育的实习实践系统用户类型:双角色,用户、管理员主要技术:Java、Vue、ElementUl、SpringBoot运行环境:Windows/Mac、JDK1.8及以上运行工具:IDEA/Eclipse数 据 库:MySQL5.7及以上版本数据库表数量:13张表......
  • Java多线程第三篇-多线程的代码相关案例
    文章目录一.单例模式1.1饿汉模式1.2懒汉模式1.3指令重排序1.4解决方法volatile二.阻塞队列2.1模拟实现阻塞队列(生产者消费者模型)三.定时器(日常开发常见的组建)3.1创建并模拟定时器实现四.线程池4.1线程池的构造方法的使用4.2模拟实现线程池五.锁策略(特点)5.......