search
HomeJavajavaTutorialHow to use SpringBoot thread pool and Java thread pool

    Usage and implementation principles of SpringBoot thread pool and Java thread pool

    Use the default thread pool

    Method 1: Through @Async The annotation call

    public class AsyncTest {
        @Async
        public void async(String name) throws InterruptedException {
            System.out.println("async" + name + " " + Thread.currentThread().getName());
            Thread.sleep(1000);
        }
    }

    needs to be added to the startup class with the @EnableAsync annotation, otherwise it will not take effect.

    @SpringBootApplication
    //@EnableAsync
    public class Test1Application {
       public static void main(String[] args) throws InterruptedException {
          ConfigurableApplicationContext run = SpringApplication.run(Test1Application.class, args);
          AsyncTest bean = run.getBean(AsyncTest.class);
          for(int index = 0; index <= 10; ++index){
             bean.async(String.valueOf(index));
          }
       }
    }

    Method 2: Directly inject ThreadPoolTaskExecutor

    No need to add @EnableAsyncAnnotation

    @SpringBootTest
    class Test1ApplicationTests {
    
       @Resource
       ThreadPoolTaskExecutor threadPoolTaskExecutor;
    
       @Test
       void contextLoads() {
          Runnable runnable = () -> {
             System.out.println(Thread.currentThread().getName());
          };
    
          for(int index = 0; index <= 10; ++index){
             threadPoolTaskExecutor.submit(runnable);
          }
       }
    
    }

    Thread pool default configuration information

    Common configurations of SpringBoot thread pool:

    spring:
      task:
        execution:
          pool:
            core-size: 8
            max-size: 16                          # 默认是 Integer.MAX_VALUE
            keep-alive: 60s                       # 当线程池中的线程数量大于 corePoolSize 时,如果某线程空闲时间超过keepAliveTime,线程将被终止
            allow-core-thread-timeout: true       # 是否允许核心线程超时,默认true
            queue-capacity: 100                   # 线程队列的大小,默认Integer.MAX_VALUE
          shutdown:
            await-termination: false              # 线程关闭等待
          thread-name-prefix: task-               # 线程名称的前缀

    The implementation principle of SpringBoot thread pool

    TaskExecutionAutoConfiguration is defined in the class ThreadPoolTaskExecutor, the internal implementation of this class It is also based on java's native ThreadPoolExecutor class. initializeExecutor()The method is called in its parent class, but in the parent class RejectedExecutionHandler is defined as private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy(); , and pass AbortPolicy into initializeExecutor() through the initialize() method.

    Note that in the TaskExecutionAutoConfiguration class, the bean names of the ThreadPoolTaskExecutor class are: applicationTaskExecutor and taskExecutor.

    // TaskExecutionAutoConfiguration#applicationTaskExecutor()
    @Lazy
    @Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,
          AsyncAnnotationBeanPostProcessor.DEFAUL
              T_TASK_EXECUTOR_BEAN_NAME })
    @ConditionalOnMissingBean(Executor.class)
    public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
       return builder.build();
    }
    // ThreadPoolTaskExecutor#initializeExecutor()
    @Override
    protected ExecutorService initializeExecutor(
          ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
    
       BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
    
       ThreadPoolExecutor executor;
       if (this.taskDecorator != null) {
          executor = new ThreadPoolExecutor(
                this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
                queue, threadFactory, rejectedExecutionHandler) {
             @Override
             public void execute(Runnable command) {
                Runnable decorated = taskDecorator.decorate(command);
                if (decorated != command) {
                   decoratedTaskMap.put(decorated, command);
                }
                super.execute(decorated);
             }
          };
       }
       else {
          executor = new ThreadPoolExecutor(
                this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
                queue, threadFactory, rejectedExecutionHandler);
    
       }
    
       if (this.allowCoreThreadTimeOut) {
          executor.allowCoreThreadTimeOut(true);
       }
    
       this.threadPoolExecutor = executor;
       return executor;
    }
    // ExecutorConfigurationSupport#initialize()
    public void initialize() {
       if (logger.isInfoEnabled()) {
          logger.info("Initializing ExecutorService" + (this.beanName != null ? " &#39;" + this.beanName + "&#39;" : ""));
       }
       if (!this.threadNamePrefixSet && this.beanName != null) {
          setThreadNamePrefix(this.beanName + "-");
       }
       this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);
    }

    Override the default thread pool

    Override the default taskExecutor object. The return type of the bean can be ThreadPoolTaskExecutor or Executor .

    @Configuration
    public class ThreadPoolConfiguration {
    
        @Bean("taskExecutor")
        public ThreadPoolTaskExecutor taskExecutor() {
            ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
            //设置线程池参数信息
            taskExecutor.setCorePoolSize(10);
            taskExecutor.setMaxPoolSize(50);
            taskExecutor.setQueueCapacity(200);
            taskExecutor.setKeepAliveSeconds(60);
            taskExecutor.setThreadNamePrefix("myExecutor--");
            taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
            taskExecutor.setAwaitTerminationSeconds(60);
            //修改拒绝策略为使用当前线程执行
            taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            //初始化线程池
            taskExecutor.initialize();
            return taskExecutor;
        }
    }

    Manage multiple thread pools

    If there are multiple thread pools, for example, defining another thread pool taskExecutor2, direct execution will report an error. At this time, you need to specify the name of the bean.

    @Bean("taskExecutor2")
    public ThreadPoolTaskExecutor taskExecutor2() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置线程池参数信息
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(50);
        taskExecutor.setQueueCapacity(200);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("myExecutor2--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        //修改拒绝策略为使用当前线程执行
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化线程池
        taskExecutor.initialize();
        return taskExecutor;
    }

    When referencing the thread pool, you need to change the variable name to the name of the bean, so that it will be searched by name.

    @Resource
    ThreadPoolTaskExecutor taskExecutor2;

    For multi-threading using the @Async annotation, just specify the bean name in the annotation.

    @Async("taskExecutor2")
        public void async(String name) throws InterruptedException {
            System.out.println("async" + name + " " + Thread.currentThread().getName());
            Thread.sleep(1000);
        }

    Four rejection strategies of thread pools

    Four commonly used thread pools in JAVA

    ThreadPoolExecutor The constructor of the class is as follows:

    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

    newCachedThreadPool

    Does not limit the maximum number of threads (maximumPoolSize=Integer.MAX_VALUE). If there are more idle threads than needed, they will be recycled, otherwise existing threads will be reused.

    new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());

    newFixedThreadPool

    Fixed-length thread pool, tasks that exceed the number of threads will wait in the queue.

    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());

    newScheduledThreadPool

    Similar to newCachedThreadPool, there is no upper limit on the number of threads, but corePoolSize can be specified. Delayed execution and periodic execution can be achieved.

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

    Periodic execution:

    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    scheduledThreadPool.scheduleAtFixedRate(()->{
       System.out.println("rate");
    }, 1, 1, TimeUnit.SECONDS);

    Delayed execution:

    scheduledThreadPool.schedule(()->{
       System.out.println("delay 3 seconds");
    }, 3, TimeUnit.SECONDS);

    newSingleThreadExecutor

    Single-threaded thread pool can realize the sequential execution of threads.

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    Four rejection policies in Java thread pool

    • CallerRunsPolicy: The thread pool allows the caller to execute.

    • AbortPolicy: If the thread pool rejects the task, an error will be reported directly.

    • DiscardPolicy: If the thread pool rejects the task, it will be discarded directly.

    • DiscardOldestPolicy: If the thread pool rejects the task, the oldest, unrun task in the thread pool will be directly discarded and the new task will be queued.

    CallerRunsPolicy

    The run method is executed directly in the main thread.

    public static class CallerRunsPolicy implements RejectedExecutionHandler {
     
        public CallerRunsPolicy() { }
     
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

    The effect is similar to:

    Runnable thread = ()->{
       System.out.println(Thread.currentThread().getName());
       try {
          Thread.sleep(0);
       } catch (InterruptedException e) {
          throw new RuntimeException(e);
       }
    };
    
    thread.run();

    AbortPolicy

    Directly throws the RejectedExecutionException exception, and indicates the task information and thread pool information. ,

    public static class AbortPolicy implements RejectedExecutionHandler {
     
        public AbortPolicy() { }
     
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

    DiscardPolicy

    does nothing.

    public static class DiscardPolicy implements RejectedExecutionHandler {
     
        public DiscardPolicy() { }
     
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

    DiscardOldestPolicy

    • ##e.getQueue().poll(): Remove the oldest task from the queue.

    • e.execute(r) : The current task is enqueued.

    • public static class DiscardOldestPolicy implements RejectedExecutionHandler {
       
          public DiscardOldestPolicy() { }
       
          public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
              if (!e.isShutdown()) {
                  e.getQueue().poll();
                  e.execute(r);
              }
          }
      }
    The principle of Java thread reuse

    javaThe thread pool saved in java.util.concurrent.ThreadPoolExecutor. Worker object, which is maintained in private final HashSet workers = new HashSet();. workQueue is a queue that stores tasks to be executed. When a new task is added to the thread pool, the task will be added to the workQueue queue.

    private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
        private static final long serialVersionUID = 6138294804551838833L;
    
        /** Thread this worker is running in.  Null if factory fails. */
        final Thread thread;
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        /** Per-thread task counter */
        volatile long completedTasks;
    
        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }
    
        /** Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);
        }
    
        // Lock methods
        //
        // The value 0 represents the unlocked state.
        // The value 1 represents the locked state.
    
        protected boolean isHeldExclusively() {
            return getState() != 0;
        }
    
        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
    
        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
    
        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }
    
        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

    The execution of the work object depends on

    runWorker(), which is different from the thread we usually write. This thread is in a loop and continuously obtains new task execution from the queue. . Therefore, threads in the thread pool can be reused, instead of ending after execution like the threads we usually use.

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

    The above is the detailed content of How to use SpringBoot thread pool and Java thread pool. For more information, please follow other related articles on the PHP Chinese website!

    Statement
    This article is reproduced at:亿速云. If there is any infringement, please contact admin@php.cn delete
    How does the class loader subsystem in the JVM contribute to platform independence?How does the class loader subsystem in the JVM contribute to platform independence?Apr 23, 2025 am 12:14 AM

    The class loader ensures the consistency and compatibility of Java programs on different platforms through unified class file format, dynamic loading, parent delegation model and platform-independent bytecode, and achieves platform independence.

    Does the Java compiler produce platform-specific code? Explain.Does the Java compiler produce platform-specific code? Explain.Apr 23, 2025 am 12:09 AM

    The code generated by the Java compiler is platform-independent, but the code that is ultimately executed is platform-specific. 1. Java source code is compiled into platform-independent bytecode. 2. The JVM converts bytecode into machine code for a specific platform, ensuring cross-platform operation but performance may be different.

    How does the JVM handle multithreading on different operating systems?How does the JVM handle multithreading on different operating systems?Apr 23, 2025 am 12:07 AM

    Multithreading is important in modern programming because it can improve program responsiveness and resource utilization and handle complex concurrent tasks. JVM ensures the consistency and efficiency of multithreads on different operating systems through thread mapping, scheduling mechanism and synchronization lock mechanism.

    What does 'platform independence' mean in the context of Java?What does 'platform independence' mean in the context of Java?Apr 23, 2025 am 12:05 AM

    Java's platform independence means that the code written can run on any platform with JVM installed without modification. 1) Java source code is compiled into bytecode, 2) Bytecode is interpreted and executed by the JVM, 3) The JVM provides memory management and garbage collection functions to ensure that the program runs on different operating systems.

    Can Java applications still encounter platform-specific bugs or issues?Can Java applications still encounter platform-specific bugs or issues?Apr 23, 2025 am 12:03 AM

    Javaapplicationscanindeedencounterplatform-specificissuesdespitetheJVM'sabstraction.Reasonsinclude:1)Nativecodeandlibraries,2)Operatingsystemdifferences,3)JVMimplementationvariations,and4)Hardwaredependencies.Tomitigatethese,developersshould:1)Conduc

    How does cloud computing impact the importance of Java's platform independence?How does cloud computing impact the importance of Java's platform independence?Apr 22, 2025 pm 07:05 PM

    Cloud computing significantly improves Java's platform independence. 1) Java code is compiled into bytecode and executed by the JVM on different operating systems to ensure cross-platform operation. 2) Use Docker and Kubernetes to deploy Java applications to improve portability and scalability.

    What role has Java's platform independence played in its widespread adoption?What role has Java's platform independence played in its widespread adoption?Apr 22, 2025 pm 06:53 PM

    Java'splatformindependenceallowsdeveloperstowritecodeonceandrunitonanydeviceorOSwithaJVM.Thisisachievedthroughcompilingtobytecode,whichtheJVMinterpretsorcompilesatruntime.ThisfeaturehassignificantlyboostedJava'sadoptionduetocross-platformdeployment,s

    How do containerization technologies (like Docker) affect the importance of Java's platform independence?How do containerization technologies (like Docker) affect the importance of Java's platform independence?Apr 22, 2025 pm 06:49 PM

    Containerization technologies such as Docker enhance rather than replace Java's platform independence. 1) Ensure consistency across environments, 2) Manage dependencies, including specific JVM versions, 3) Simplify the deployment process to make Java applications more adaptable and manageable.

    See all articles

    Hot AI Tools

    Undresser.AI Undress

    Undresser.AI Undress

    AI-powered app for creating realistic nude photos

    AI Clothes Remover

    AI Clothes Remover

    Online AI tool for removing clothes from photos.

    Undress AI Tool

    Undress AI Tool

    Undress images for free

    Clothoff.io

    Clothoff.io

    AI clothes remover

    Video Face Swap

    Video Face Swap

    Swap faces in any video effortlessly with our completely free AI face swap tool!

    Hot Tools

    SublimeText3 Mac version

    SublimeText3 Mac version

    God-level code editing software (SublimeText3)

    Safe Exam Browser

    Safe Exam Browser

    Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

    Atom editor mac version download

    Atom editor mac version download

    The most popular open source editor

    EditPlus Chinese cracked version

    EditPlus Chinese cracked version

    Small size, syntax highlighting, does not support code prompt function

    SecLists

    SecLists

    SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.