
001/*- 002 * #%L 003 * HAPI FHIR Storage api 004 * %% 005 * Copyright (C) 2014 - 2025 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.util; 021 022import ca.uhn.fhir.jpa.search.reindex.BlockPolicy; 023import jakarta.annotation.Nonnull; 024import org.apache.commons.lang3.Validate; 025import org.springframework.core.task.TaskDecorator; 026import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 027 028import java.util.concurrent.RejectedExecutionHandler; 029 030public final class ThreadPoolUtil { 031 private ThreadPoolUtil() {} 032 033 @Nonnull 034 public static ThreadPoolTaskExecutor newThreadPool( 035 int theCorePoolSize, int theMaxPoolSize, String theThreadNamePrefix) { 036 return newThreadPool(theCorePoolSize, theMaxPoolSize, theThreadNamePrefix, 0); 037 } 038 039 @Nonnull 040 public static ThreadPoolTaskExecutor newThreadPool( 041 int theCorePoolSize, int theMaxPoolSize, String theThreadNamePrefix, int theQueueCapacity) { 042 return newThreadPool( 043 theCorePoolSize, theMaxPoolSize, theThreadNamePrefix, theQueueCapacity, null, new BlockPolicy()); 044 } 045 046 @Nonnull 047 public static ThreadPoolTaskExecutor newThreadPool( 048 int theCorePoolSize, 049 int theMaxPoolSize, 050 String theThreadNamePrefix, 051 int theQueueCapacity, 052 RejectedExecutionHandler theRejectedExecutionHandler) { 053 return newThreadPool( 054 theCorePoolSize, 055 theMaxPoolSize, 056 theThreadNamePrefix, 057 theQueueCapacity, 058 null, 059 theRejectedExecutionHandler); 060 } 061 062 @Nonnull 063 public static ThreadPoolTaskExecutor newThreadPool( 064 int theCorePoolSize, 065 int theMaxPoolSize, 066 String theThreadNamePrefix, 067 int theQueueCapacity, 068 TaskDecorator taskDecorator, 069 RejectedExecutionHandler theRejectedExecutionHandler) { 070 Validate.isTrue( 071 theCorePoolSize == theMaxPoolSize || theQueueCapacity == 0, 072 "If the queue capacity is greater than 0, core pool size needs to match max pool size or the system won't grow the queue"); 073 Validate.isTrue(theThreadNamePrefix.endsWith("-"), "Thread pool prefix name must end with a hyphen"); 074 ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor(); 075 asyncTaskExecutor.setCorePoolSize(theCorePoolSize); 076 asyncTaskExecutor.setMaxPoolSize(theMaxPoolSize); 077 asyncTaskExecutor.setQueueCapacity(theQueueCapacity); 078 asyncTaskExecutor.setAllowCoreThreadTimeOut(true); 079 asyncTaskExecutor.setThreadNamePrefix(theThreadNamePrefix); 080 asyncTaskExecutor.setRejectedExecutionHandler(theRejectedExecutionHandler); 081 asyncTaskExecutor.setTaskDecorator(taskDecorator); 082 asyncTaskExecutor.initialize(); 083 return asyncTaskExecutor; 084 } 085}