Vert.x Event Loops

Vert.x Event Loops

In this tutorial, we are going to discuss about the Vert.x Event Loops. We know already what is vertx and verticles are, but we did not look into event loops yet.

Vert.x uses an event-driven, non-blocking model that heavily relies on event loops to handle concurrency. The event loop in Vert.x is inspired by the design of the Reactor Pattern, similar to what is used in frameworks like Node.js. It allows Vert.x to handle many connections and events efficiently without requiring multiple threads for each task.

By default, verticles code is executed on a non-blocking event loop thread. To understand what Vert.x event loops are, we have to dive a bit into the model of threads and concurrency.

If you run some code, the code is executed on a thread on the CPU of your computer. If the application would have only one thread, nothing can happen in parallel and other requests would have to wait all the time until the thread is free.

Shared Memory 1

To avoid this issue, a software program runs normally on multiple threads and they can execute tasks in parallel. This concept is known as multithreading. It is fine to run more threads as a software program, but when a lot of concurrent requests are happening, then a lot of threads have to be created and depending on the request they would need to wait until the response returns.

Blocking IO

This causes a lot of wasted CPU time as the threads are not fully utilized and at some point one CPU will not accept more threads. That means the power is limited. That means the power is limited. The solution to avoid wasting time is called non-blocking I/O.

The threads which are executing non-blocking I/O are called event loops and Vertx is utilizing this concept heavily.

Vert.x Event Loops

In the above picture you can see that all events are lined up in a queue and the event loop thread is processing them as fast as possible without any waiting time. The rule number 1 here is to never block the event loop threads to ensure that all events can be processed as fast as possible.

Each vertx verticle is scheduled on an event loop thread. With that inside a verticle thread, Safety is guaranteed and concurrency can happen without concurrent access issues. Sometimes there are operations which are blocking by nature, like traditional relational database access, file access or just waiting for network responses as blocking operations cannot be avoided. It is possible to execute these kind of events on so called worker threads. Additionally, Vertx has a built in thread block checker that will warn when the event loop was blocked. If you see this kind of warnings, make sure to fix it, otherwise your application might not behave as expected. Okay. We learned about the theoretical part. What about writing some code? We are all here for this, right?

So we are starting by creating a new package with the name event loop. And in here we are creating a new class called EventLoopExample.

package com.ashok.vertx.vertx_starter.eventloops;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
/**
 *
 * @author ashok.mariyala
 *
 */
public class EventLoopExample extends AbstractVerticle {

  private static final Logger LOG = LoggerFactory.getLogger(EventLoopExample.class);

  public static void main(String[] args) {
    var vertx = Vertx.vertx();
    vertx.deployVerticle(new EventLoopExample());
  }

  @Override
  public void start(final Promise<Void> startPromise) throws Exception {
    LOG.debug("Start {}", getClass().getName());
    startPromise.complete();
    // Do not do this inside a verticle
    Thread.sleep(5000);
  }
}

The EventLoopExample class is extending from AbstractVerticle class. And additionally we are adding a public static void main() method. Inside the main method we are creating a variable vertx which is equal to Vertx.vertx(). So we are creating a vertx instance and then we are deploying the EventLoopExample verticle using vertx.deployVerticle(new EventLoopExample()).

Next, we are overriding the Start method and we are adding a logger into it. So we get some indication when the class is started.

Now we are starting with rule number 1. Do you remember what it was? Never block the event loop. So what can we do to block the event loop? For example, we could add a Thread.sleep(). Thread.sleep is a blocking call and will block the event loop so it can do nothing else. So we are adding a Thread.sleep() in our start method of 5 seconds. So the verticle is deployed and then we are sleeping in there.

12:06:44 pm: Executing ':EventLoopExample.main()'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes

> Task :EventLoopExample.main()
[vert.x-eventloop-thread-0] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 2110 ms, time limit is 2000 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 3111 ms, time limit is 2000 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 4117 ms, time limit is 2000 ms

So we should see a thread blocked warning. We see it’s running on vertx event loop thread 0. We can clearly see that vertx verticles are deployed on event loops.

It is possible to configure some settings in the vertx options, so when creating the vertx instance we can define a new VertxOptions object.

package com.ashok.vertx.vertx_starter.eventloops;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
/**
 *
 * @author ashok.mariyala
 *
 */
public class EventLoopExample extends AbstractVerticle {

  private static final Logger LOG = LoggerFactory.getLogger(EventLoopExample.class);

  public static void main(String[] args) {
    var vertx = Vertx.vertx(
      new VertxOptions()
        .setMaxEventLoopExecuteTime(500)
        .setMaxEventLoopExecuteTimeUnit(TimeUnit.MILLISECONDS)
        .setBlockedThreadCheckInterval(1)
        .setBlockedThreadCheckIntervalUnit(TimeUnit.SECONDS)
    );
    vertx.deployVerticle(new EventLoopExample()
    );
  }

  @Override
  public void start(final Promise<Void> startPromise) throws Exception {
    LOG.error("Start {}", getClass().getName());
    startPromise.complete();
    // Do not do this inside a verticle
    Thread.sleep(5000);
  }
}

The VertxOptions has multiple properties.

setMaxEventLoopExecuteTime:

This is a setting for how long the event loop can be blocked before the blocked thread checker would return a warning. The default setting here is 2 seconds. In my opinion, this is too high, so I would recommend to set this a bit lower. So i used 0.5 seconds.

setMaxEventLoopExecuteTimeUnit:

Time unit for the setMaxEventLoopExecuteTime. The default value is TimeUnit.NANOSECONDS

setBlockedThreadCheckInterval

Sets the value of blocked thread check period.

setBlockedThreadCheckIntervalUnit

Time unit for the setBlockedThreadCheckInterval. The default value is TimeUnit.MILLISECONDS

Okay, now let’s start our application and see if this blocked thread checker warning is appearing. We set the interval to 500 milliseconds and we are blocking for 5 seconds.

12:23:44 pm: Executing ':EventLoopExample.main()'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes

> Task :EventLoopExample.main()
[vert.x-eventloop-thread-0] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 1210 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 2216 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 3221 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 4225 ms, time limit is 500 ms

So we see in the log output thread has been blocked for 1210 milliseconds and the time limit is 500 milliseconds.

Now let’s see what happens when we deploy multiple vertx of the same type using DeploymentOptions.

package com.ashok.vertx.vertx_starter.eventloops;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
/**
 *
 * @author ashok.mariyala
 *
 */
public class EventLoopExample extends AbstractVerticle {

  private static final Logger LOG = LoggerFactory.getLogger(EventLoopExample.class);

  public static void main(String[] args) {
    var vertx = Vertx.vertx(
      new VertxOptions()
        .setMaxEventLoopExecuteTime(500)
        .setMaxEventLoopExecuteTimeUnit(TimeUnit.MILLISECONDS)
        .setBlockedThreadCheckInterval(1)
        .setBlockedThreadCheckIntervalUnit(TimeUnit.SECONDS)
    );
    vertx.deployVerticle(EventLoopExample.class.getName(),
      new DeploymentOptions().setInstances(4)
    );
  }

  @Override
  public void start(final Promise<Void> startPromise) throws Exception {
    LOG.error("Start {}", getClass().getName());
    startPromise.complete();
    // Do not do this inside a verticle
    Thread.sleep(5000);
  }
}
12:30:44 pm: Executing ':EventLoopExample.main()'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes

> Task :EventLoopExample.main()
[vert.x-eventloop-thread-1] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vert.x-eventloop-thread-2] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vert.x-eventloop-thread-4] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vert.x-eventloop-thread-3] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-3,5,main] has been blocked for 1218 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-4,5,main] has been blocked for 1218 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 1218 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 1218 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-3,5,main] has been blocked for 2220 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-4,5,main] has been blocked for 2220 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 2221 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 2221 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-3,5,main] has been blocked for 3224 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-4,5,main] has been blocked for 3224 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 3224 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 3224 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-3,5,main] has been blocked for 4227 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-4,5,main] has been blocked for 4227 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 4228 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 4227 ms, time limit is 500 ms

Now we see four times a start output on event loop thread 1, 2, 3 and 4. Additionally, we see many more blocked thread checker warnings because each event loop thread is blocked. So if there are 4 verticle instances, they are deployed on 4 different Vert.x event loops.

By changing the vertx options, we can set the event loop pool size using setEventLoopPoolSize method. Let’s see what happens if we set it to 2.

package com.ashok.vertx.vertx_starter.eventloops;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
/**
 *
 * @author ashok.mariyala
 *
 */
public class EventLoopExample extends AbstractVerticle {

  private static final Logger LOG = LoggerFactory.getLogger(EventLoopExample.class);

  public static void main(String[] args) {
    var vertx = Vertx.vertx(
      new VertxOptions()
        .setMaxEventLoopExecuteTime(500)
        .setMaxEventLoopExecuteTimeUnit(TimeUnit.MILLISECONDS)
        .setBlockedThreadCheckInterval(1)
        .setBlockedThreadCheckIntervalUnit(TimeUnit.SECONDS)
        .setEventLoopPoolSize(2)
    );
    vertx.deployVerticle(EventLoopExample.class.getName(),
      new DeploymentOptions().setInstances(4)
    );
  }

  @Override
  public void start(final Promise<Void> startPromise) throws Exception {
    LOG.error("Start {}", getClass().getName());
    startPromise.complete();
    // Do not do this inside a verticle
    Thread.sleep(5000);
  }
}
12:35:17 pm: Executing ':EventLoopExample.main()'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes

> Task :EventLoopExample.main()
[vert.x-eventloop-thread-0] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vert.x-eventloop-thread-1] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 1329 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 1328 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 2331 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 2331 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 3337 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 3336 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 4340 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 4340 ms, time limit is 500 ms
[vert.x-eventloop-thread-1] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vert.x-eventloop-thread-0] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 1319 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 1319 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 2321 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 2321 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 3323 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 3323 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 4325 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 4325 ms, time limit is 500 ms

Then we can see 2 verticles are started. Then we see the warnings of the blocked thread checker and then we see again 2 verticles are started. That means now that 4 verticles are competing for resources on 2 event loop threads. So this setting doesn’t make sense at all. Also, make sure to have more Vert.x event loops as you have verticles. Otherwise it does not make sense to scale them by default.

Vertx is adding a lot of event loops already so you don’t have to tweak it if you don’t have specific use cases for it.

package com.ashok.vertx.vertx_starter.eventloops;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
/**
 *
 * @author ashok.mariyala
 *
 */
public class EventLoopExample extends AbstractVerticle {

  private static final Logger LOG = LoggerFactory.getLogger(EventLoopExample.class);

  public static void main(String[] args) {
    var vertx = Vertx.vertx(
      new VertxOptions()
        .setMaxEventLoopExecuteTime(500)
        .setMaxEventLoopExecuteTimeUnit(TimeUnit.MILLISECONDS)
        .setBlockedThreadCheckInterval(1)
        .setBlockedThreadCheckIntervalUnit(TimeUnit.SECONDS)
        .setEventLoopPoolSize(4)
    );
    vertx.deployVerticle(EventLoopExample.class.getName(),
      new DeploymentOptions().setInstances(4)
    );
  }

  @Override
  public void start(final Promise<Void> startPromise) throws Exception {
    LOG.error("Start {}", getClass().getName());
    startPromise.complete();
    // Do not do this inside a verticle
    Thread.sleep(5000);
  }
}
12:38:58 pm: Executing ':EventLoopExample.main()'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes

> Task :EventLoopExample.main()
[vert.x-eventloop-thread-2] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vert.x-eventloop-thread-3] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vert.x-eventloop-thread-1] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vert.x-eventloop-thread-0] DEBUG com.ashok.vertx.vertx_starter.eventloops.EventLoopExample - Start com.ashok.vertx.vertx_starter.eventloops.EventLoopExample
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 1413 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-3,5,main] has been blocked for 1413 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 1413 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 1410 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 2418 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-3,5,main] has been blocked for 2417 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 2418 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 2414 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 3423 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-3,5,main] has been blocked for 3423 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 3423 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 3420 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 4428 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-3,5,main] has been blocked for 4427 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 4428 ms, time limit is 500 ms
[vertx-blocked-thread-checker] WARN io.vertx.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-0,5,main] has been blocked for 4424 ms, time limit is 500 ms

To sum it up, remember rule number 1 and never block the event loop. Also, be careful when scaling your verticles and remember the amount of available Vert.x event loops.

Best Practices
  • Avoid Blocking the Event Loop: Since Vert.x relies on the event loop to handle tasks, blocking operations (like a long computation or database access) should be avoided in standard verticles. Instead, use worker verticles for blocking tasks.
  • Leverage Asynchronous APIs: Vert.x provides asynchronous APIs for most operations. Use these non-blocking APIs to keep the event loop free to handle more events.
  • Understand Event Loop Threading Model: Vert.x does not use traditional concurrency models with locks and shared memory. Instead, it relies on event loops and message passing, which simplifies concurrency management.
Key Concepts
  • Concurrency Model: Vert.x achieves concurrency by processing events in a non-blocking way using event loops rather than using traditional multithreading.
  • Context Switching: Each verticle instance runs on a specific event loop, meaning no context switching between threads unless explicitly moved to a worker thread.
  • Thread Safety: Since each verticle runs on a single event loop thread, verticle code is generally thread-safe without requiring locks, as long as you don’t share state between verticles.
Advantages
  • High throughput for I/O-bound applications.
  • Minimal thread context switching, which reduces overhead.
  • Simplified concurrency model compared to traditional multithreading.

That’s all about the Vert.x Event Loops with example. If you have any queries or feedback, please write us email at contact@waytoeasylearn.com. Enjoy learning, Enjoy Vert.x tutorials..!!

Vert.x Event Loops
Scroll to top