001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.messaging.simp.config;
018
019import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
020import org.springframework.util.Assert;
021
022/**
023 * A registration class for customizing the properties of {@link ThreadPoolTaskExecutor}.
024 *
025 * @author Rossen Stoyanchev
026 * @author Juergen Hoeller
027 * @since 4.0
028 */
029public class TaskExecutorRegistration {
030
031        private final ThreadPoolTaskExecutor taskExecutor;
032
033        private Integer corePoolSize;
034
035        private Integer maxPoolSize;
036
037        private Integer keepAliveSeconds;
038
039        private Integer queueCapacity;
040
041
042        /**
043         * Create a new {@code TaskExecutorRegistration} for a default
044         * {@link ThreadPoolTaskExecutor}.
045         */
046        public TaskExecutorRegistration() {
047                this.taskExecutor = new ThreadPoolTaskExecutor();
048                this.taskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2);
049                this.taskExecutor.setAllowCoreThreadTimeOut(true);
050        }
051
052        /**
053         * Create a new {@code TaskExecutorRegistration} for a given
054         * {@link ThreadPoolTaskExecutor}.
055         * @param taskExecutor the executor to use
056         */
057        public TaskExecutorRegistration(ThreadPoolTaskExecutor taskExecutor) {
058                Assert.notNull(taskExecutor, "ThreadPoolTaskExecutor must not be null");
059                this.taskExecutor = taskExecutor;
060        }
061
062
063        /**
064         * Set the core pool size of the ThreadPoolExecutor.
065         * <p><strong>NOTE:</strong> The core pool size is effectively the max pool size
066         * when an unbounded {@link #queueCapacity(int) queueCapacity} is configured
067         * (the default). This is essentially the "Unbounded queues" strategy as explained
068         * in {@link java.util.concurrent.ThreadPoolExecutor ThreadPoolExecutor}. When
069         * this strategy is used, the {@link #maxPoolSize(int) maxPoolSize} is ignored.
070         * <p>By default this is set to twice the value of
071         * {@link Runtime#availableProcessors()}. In an application where tasks do not
072         * block frequently, the number should be closer to or equal to the number of
073         * available CPUs/cores.
074         */
075        public TaskExecutorRegistration corePoolSize(int corePoolSize) {
076                this.corePoolSize = corePoolSize;
077                return this;
078        }
079
080        /**
081         * Set the max pool size of the ThreadPoolExecutor.
082         * <p><strong>NOTE:</strong> When an unbounded
083         * {@link #queueCapacity(int) queueCapacity} is configured (the default), the
084         * max pool size is effectively ignored. See the "Unbounded queues" strategy
085         * in {@link java.util.concurrent.ThreadPoolExecutor ThreadPoolExecutor} for
086         * more details.
087         * <p>By default this is set to {@code Integer.MAX_VALUE}.
088         */
089        public TaskExecutorRegistration maxPoolSize(int maxPoolSize) {
090                this.maxPoolSize = maxPoolSize;
091                return this;
092        }
093
094        /**
095         * Set the time limit for which threads may remain idle before being terminated.
096         * If there are more than the core number of threads currently in the pool,
097         * after waiting this amount of time without processing a task, excess threads
098         * will be terminated. This overrides any value set in the constructor.
099         * <p>By default this is set to 60.
100         */
101        public TaskExecutorRegistration keepAliveSeconds(int keepAliveSeconds) {
102                this.keepAliveSeconds = keepAliveSeconds;
103                return this;
104        }
105
106        /**
107         * Set the queue capacity for the ThreadPoolExecutor.
108         * <p><strong>NOTE:</strong> when an unbounded {@code queueCapacity} is configured
109         * (the default), the core pool size is effectively the max pool size. This is
110         * essentially the "Unbounded queues" strategy as explained in
111         * {@link java.util.concurrent.ThreadPoolExecutor ThreadPoolExecutor}. When
112         * this strategy is used, the {@link #maxPoolSize(int) maxPoolSize} is ignored.
113         * <p>By default this is set to {@code Integer.MAX_VALUE}.
114         */
115        public TaskExecutorRegistration queueCapacity(int queueCapacity) {
116                this.queueCapacity = queueCapacity;
117                return this;
118        }
119
120
121        protected ThreadPoolTaskExecutor getTaskExecutor() {
122                if (this.corePoolSize != null) {
123                        this.taskExecutor.setCorePoolSize(this.corePoolSize);
124                }
125                if (this.maxPoolSize != null) {
126                        this.taskExecutor.setMaxPoolSize(this.maxPoolSize);
127                }
128                if (this.keepAliveSeconds != null) {
129                        this.taskExecutor.setKeepAliveSeconds(this.keepAliveSeconds);
130                }
131                if (this.queueCapacity != null) {
132                        this.taskExecutor.setQueueCapacity(this.queueCapacity);
133                }
134                return this.taskExecutor;
135        }
136
137}