ScheduledExecutorService consumes 100% CPU when corePoolSize = 0
I've ran into an interesting issue in production.
I've had the following ScheduledThreadPool
allocation code:
ScheduledExecutorService executorService =
Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() - 1);
The thread pool was processing some tasks from the queue periodically. And everything was working fine till the moment when the service was deployed on a single core environment. Apparently, the line above converted to:
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
Since then, the JVM process CPU utilization was constantly around 100%. The moment I've changed Runtime.getRuntime().availableProcessors() - 1
to constant 1
the issue have gone.
It took sometime to find out the root cause, but still I don't know the reason behind it. ScheduledExecutorService
JavaDoc states:
/**
* Creates a thread pool that can schedule commands to run after a
* given delay, or to execute periodically.
* @param corePoolSize the number of threads to keep in the pool,
* even if they are idle
* @return a newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
Basically, 0 (zero) is a valid argument for the thread pool instantiation, but it works super weird with this value.
Can please someone explain why so?
Simple and verifiable test case
import java.util.Queue;
import java.util.concurrent.*;
public class Test {
public static void main(String args) throws InterruptedException {
MessageTaskExecutor asyncEmailGatewayTaskExecutor = new MessageTaskExecutor();
// Infinitely add new tasks to the queue every second
for (int i = 1; ; i++) {
System.out.println(String.format("Adding message #%s to the queue", i));
asyncEmailGatewayTaskExecutor.putMessageIntoQueue(i);
Thread.sleep(1_000);
}
}
static class MessageTaskExecutor {
static final int INITIAL_DELAY_SECONDS = 1;
static final int PROCESSING_RATE_MILLISECONDS = 5_000;
final Queue<Runnable> messageQueue = new ArrayBlockingQueue<>(1_000_000);
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
MessageTaskExecutor() {
// Scavenging Message Tasks Queue every 'PROCESSING_RATE_MILLISECONDS'. Initial delay is fixed for 'INITIAL_DELAY_SECONDS'
executorService.schedule(this::processEmailTasks, INITIAL_DELAY_SECONDS, TimeUnit.SECONDS);
}
void putMessageIntoQueue(int messageId) {
Runnable messageTask = () -> System.out.println(String.format("Message #%s is getting processed!", messageId));
messageQueue.offer(messageTask);
}
void processEmailTasks() {
System.out.println(String.format("There are %s messages in the queue. Processing the messages...", messageQueue.size()));
// Processing messages queue
while (!messageQueue.isEmpty()) {
executorService.submit(messageQueue.poll()); // Submitting task to executor service
}
// Re-scheduling processing job
executorService.schedule(this::processEmailTasks, PROCESSING_RATE_MILLISECONDS, TimeUnit.MILLISECONDS);
}
}
}
This code allocates ~30 MB and JVM process consumes ~100% CPU on a single-core virtual machine (tested on Win 7/CentOS 7). JDK 1.8.0.181.
By changing field:
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
to:
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
CPU consumption goes down to normal 3-5%.
java performance threadpool threadpoolexecutor
add a comment |
I've ran into an interesting issue in production.
I've had the following ScheduledThreadPool
allocation code:
ScheduledExecutorService executorService =
Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() - 1);
The thread pool was processing some tasks from the queue periodically. And everything was working fine till the moment when the service was deployed on a single core environment. Apparently, the line above converted to:
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
Since then, the JVM process CPU utilization was constantly around 100%. The moment I've changed Runtime.getRuntime().availableProcessors() - 1
to constant 1
the issue have gone.
It took sometime to find out the root cause, but still I don't know the reason behind it. ScheduledExecutorService
JavaDoc states:
/**
* Creates a thread pool that can schedule commands to run after a
* given delay, or to execute periodically.
* @param corePoolSize the number of threads to keep in the pool,
* even if they are idle
* @return a newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
Basically, 0 (zero) is a valid argument for the thread pool instantiation, but it works super weird with this value.
Can please someone explain why so?
Simple and verifiable test case
import java.util.Queue;
import java.util.concurrent.*;
public class Test {
public static void main(String args) throws InterruptedException {
MessageTaskExecutor asyncEmailGatewayTaskExecutor = new MessageTaskExecutor();
// Infinitely add new tasks to the queue every second
for (int i = 1; ; i++) {
System.out.println(String.format("Adding message #%s to the queue", i));
asyncEmailGatewayTaskExecutor.putMessageIntoQueue(i);
Thread.sleep(1_000);
}
}
static class MessageTaskExecutor {
static final int INITIAL_DELAY_SECONDS = 1;
static final int PROCESSING_RATE_MILLISECONDS = 5_000;
final Queue<Runnable> messageQueue = new ArrayBlockingQueue<>(1_000_000);
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
MessageTaskExecutor() {
// Scavenging Message Tasks Queue every 'PROCESSING_RATE_MILLISECONDS'. Initial delay is fixed for 'INITIAL_DELAY_SECONDS'
executorService.schedule(this::processEmailTasks, INITIAL_DELAY_SECONDS, TimeUnit.SECONDS);
}
void putMessageIntoQueue(int messageId) {
Runnable messageTask = () -> System.out.println(String.format("Message #%s is getting processed!", messageId));
messageQueue.offer(messageTask);
}
void processEmailTasks() {
System.out.println(String.format("There are %s messages in the queue. Processing the messages...", messageQueue.size()));
// Processing messages queue
while (!messageQueue.isEmpty()) {
executorService.submit(messageQueue.poll()); // Submitting task to executor service
}
// Re-scheduling processing job
executorService.schedule(this::processEmailTasks, PROCESSING_RATE_MILLISECONDS, TimeUnit.MILLISECONDS);
}
}
}
This code allocates ~30 MB and JVM process consumes ~100% CPU on a single-core virtual machine (tested on Win 7/CentOS 7). JDK 1.8.0.181.
By changing field:
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
to:
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
CPU consumption goes down to normal 3-5%.
java performance threadpool threadpoolexecutor
add a comment |
I've ran into an interesting issue in production.
I've had the following ScheduledThreadPool
allocation code:
ScheduledExecutorService executorService =
Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() - 1);
The thread pool was processing some tasks from the queue periodically. And everything was working fine till the moment when the service was deployed on a single core environment. Apparently, the line above converted to:
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
Since then, the JVM process CPU utilization was constantly around 100%. The moment I've changed Runtime.getRuntime().availableProcessors() - 1
to constant 1
the issue have gone.
It took sometime to find out the root cause, but still I don't know the reason behind it. ScheduledExecutorService
JavaDoc states:
/**
* Creates a thread pool that can schedule commands to run after a
* given delay, or to execute periodically.
* @param corePoolSize the number of threads to keep in the pool,
* even if they are idle
* @return a newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
Basically, 0 (zero) is a valid argument for the thread pool instantiation, but it works super weird with this value.
Can please someone explain why so?
Simple and verifiable test case
import java.util.Queue;
import java.util.concurrent.*;
public class Test {
public static void main(String args) throws InterruptedException {
MessageTaskExecutor asyncEmailGatewayTaskExecutor = new MessageTaskExecutor();
// Infinitely add new tasks to the queue every second
for (int i = 1; ; i++) {
System.out.println(String.format("Adding message #%s to the queue", i));
asyncEmailGatewayTaskExecutor.putMessageIntoQueue(i);
Thread.sleep(1_000);
}
}
static class MessageTaskExecutor {
static final int INITIAL_DELAY_SECONDS = 1;
static final int PROCESSING_RATE_MILLISECONDS = 5_000;
final Queue<Runnable> messageQueue = new ArrayBlockingQueue<>(1_000_000);
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
MessageTaskExecutor() {
// Scavenging Message Tasks Queue every 'PROCESSING_RATE_MILLISECONDS'. Initial delay is fixed for 'INITIAL_DELAY_SECONDS'
executorService.schedule(this::processEmailTasks, INITIAL_DELAY_SECONDS, TimeUnit.SECONDS);
}
void putMessageIntoQueue(int messageId) {
Runnable messageTask = () -> System.out.println(String.format("Message #%s is getting processed!", messageId));
messageQueue.offer(messageTask);
}
void processEmailTasks() {
System.out.println(String.format("There are %s messages in the queue. Processing the messages...", messageQueue.size()));
// Processing messages queue
while (!messageQueue.isEmpty()) {
executorService.submit(messageQueue.poll()); // Submitting task to executor service
}
// Re-scheduling processing job
executorService.schedule(this::processEmailTasks, PROCESSING_RATE_MILLISECONDS, TimeUnit.MILLISECONDS);
}
}
}
This code allocates ~30 MB and JVM process consumes ~100% CPU on a single-core virtual machine (tested on Win 7/CentOS 7). JDK 1.8.0.181.
By changing field:
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
to:
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
CPU consumption goes down to normal 3-5%.
java performance threadpool threadpoolexecutor
I've ran into an interesting issue in production.
I've had the following ScheduledThreadPool
allocation code:
ScheduledExecutorService executorService =
Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() - 1);
The thread pool was processing some tasks from the queue periodically. And everything was working fine till the moment when the service was deployed on a single core environment. Apparently, the line above converted to:
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
Since then, the JVM process CPU utilization was constantly around 100%. The moment I've changed Runtime.getRuntime().availableProcessors() - 1
to constant 1
the issue have gone.
It took sometime to find out the root cause, but still I don't know the reason behind it. ScheduledExecutorService
JavaDoc states:
/**
* Creates a thread pool that can schedule commands to run after a
* given delay, or to execute periodically.
* @param corePoolSize the number of threads to keep in the pool,
* even if they are idle
* @return a newly created scheduled thread pool
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
Basically, 0 (zero) is a valid argument for the thread pool instantiation, but it works super weird with this value.
Can please someone explain why so?
Simple and verifiable test case
import java.util.Queue;
import java.util.concurrent.*;
public class Test {
public static void main(String args) throws InterruptedException {
MessageTaskExecutor asyncEmailGatewayTaskExecutor = new MessageTaskExecutor();
// Infinitely add new tasks to the queue every second
for (int i = 1; ; i++) {
System.out.println(String.format("Adding message #%s to the queue", i));
asyncEmailGatewayTaskExecutor.putMessageIntoQueue(i);
Thread.sleep(1_000);
}
}
static class MessageTaskExecutor {
static final int INITIAL_DELAY_SECONDS = 1;
static final int PROCESSING_RATE_MILLISECONDS = 5_000;
final Queue<Runnable> messageQueue = new ArrayBlockingQueue<>(1_000_000);
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
MessageTaskExecutor() {
// Scavenging Message Tasks Queue every 'PROCESSING_RATE_MILLISECONDS'. Initial delay is fixed for 'INITIAL_DELAY_SECONDS'
executorService.schedule(this::processEmailTasks, INITIAL_DELAY_SECONDS, TimeUnit.SECONDS);
}
void putMessageIntoQueue(int messageId) {
Runnable messageTask = () -> System.out.println(String.format("Message #%s is getting processed!", messageId));
messageQueue.offer(messageTask);
}
void processEmailTasks() {
System.out.println(String.format("There are %s messages in the queue. Processing the messages...", messageQueue.size()));
// Processing messages queue
while (!messageQueue.isEmpty()) {
executorService.submit(messageQueue.poll()); // Submitting task to executor service
}
// Re-scheduling processing job
executorService.schedule(this::processEmailTasks, PROCESSING_RATE_MILLISECONDS, TimeUnit.MILLISECONDS);
}
}
}
This code allocates ~30 MB and JVM process consumes ~100% CPU on a single-core virtual machine (tested on Win 7/CentOS 7). JDK 1.8.0.181.
By changing field:
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
to:
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
CPU consumption goes down to normal 3-5%.
java performance threadpool threadpoolexecutor
java performance threadpool threadpoolexecutor
asked Nov 20 '18 at 20:42
Mikhail Kholodkov
4,13952546
4,13952546
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
This is a known bug: JDK-8129861. It has been fixed in JDK 9.
The workaround is to set core pool size at least 1:
int corePoolSize = Math.max(Runtime.getRuntime().availableProcessors() - 1, 1);
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53401197%2fscheduledexecutorservice-consumes-100-cpu-when-corepoolsize-0%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
This is a known bug: JDK-8129861. It has been fixed in JDK 9.
The workaround is to set core pool size at least 1:
int corePoolSize = Math.max(Runtime.getRuntime().availableProcessors() - 1, 1);
add a comment |
This is a known bug: JDK-8129861. It has been fixed in JDK 9.
The workaround is to set core pool size at least 1:
int corePoolSize = Math.max(Runtime.getRuntime().availableProcessors() - 1, 1);
add a comment |
This is a known bug: JDK-8129861. It has been fixed in JDK 9.
The workaround is to set core pool size at least 1:
int corePoolSize = Math.max(Runtime.getRuntime().availableProcessors() - 1, 1);
This is a known bug: JDK-8129861. It has been fixed in JDK 9.
The workaround is to set core pool size at least 1:
int corePoolSize = Math.max(Runtime.getRuntime().availableProcessors() - 1, 1);
answered Nov 20 '18 at 20:53
apangin
48.9k795124
48.9k795124
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53401197%2fscheduledexecutorservice-consumes-100-cpu-when-corepoolsize-0%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown