Guava RateLimiter to control the frequency of events

5 09 2015

Having a long running process, consisting of many small, fast steps, updating its listeners after processing each step?

Assume that you process the list of thousands items in a thread and want to show each processed item to the user. Processing each item is very fast, so the updates will be send to the GUI very frequently. You do not want to notify the GUI listener so often. But you want to refresh the gui twice per second, not more.

This is what RateLimiter can do: limit the access to the resources to prevent too frequent calls.

GuiUpdater

For sake of simplicity my GuiUpdater just prints message with a timestamp on System.out:

public class ProgressGuiUpdater implements GuiUpdater{
    @Override
    public void updateGui(String message) {
        System.out.println(LocalDateTime.now().toLocalTime() + ": " + message);
    }
}

The LongRunningProcess

My process consists of many small steps. In each step I update the GUI via the injected updater. Calling this loop with 15000 iterations lasts around 3 seconds.

@Override
public void run() {
    for (int i = 0; i < stepsCount; i++) {
        guiUpdater.updateGui("This is the item number" + i);
    }
}

GUI gets updated around 5000 times per second. For average app it is way too often. This is the fragment of console output (mind the timestamps):

16:53:10.025: This is item number 1
16:53:10.026: This is item number 2
16:53:10.026: This is item number 3
16:53:10.027: This is item number 4
16:53:10.027: This is item number 5
16:53:10.028: This is item number 6
16:53:10.029: This is item number 7

Limit the updates frequency

RateLimiter will limit the access to the updater. It will stop the thread execution until the specified time will pass (remember the semaphores in Java?). After it will acquire the access, the thread will be unblocked and updater method will be called. Before calling the updater method I need to acquire the RateLimiter:

@Override
public void run() {
    for (int i = 0; i < stepsCount; i++) {
        double waitTime = rateLimiter.acquire();
        guiUpdater.updateGui("This is the item number " + i + " (I've waited for acquire for " + waitTime + " seconds)");
    }
}

The creation of rateLimiter is:

RateLimiter.create(2.0)

As a parameter I pass the number of times per second the rate limiter can acquire the lock.

The result of that configuration is (mind the timestamps and waiting times):

18:09:15.364: This is the item number 0 (I've waited for acquire for 0.0 seconds)
18:09:15.539: This is the item number 1 (I've waited for acquire for 0.113705 seconds)
18:09:16.028: This is the item number 2 (I've waited for acquire for 0.486599 seconds)
18:09:16.527: This is the item number 3 (I've waited for acquire for 0.498785 seconds)
18:09:17.027: This is the item number 4 (I've waited for acquire for 0.498922 seconds)
18:09:17.527: This is the item number 5 (I've waited for acquire for 0.49909 seconds)
18:09:18.027: This is the item number 6 (I've waited for acquire for 0.499802 seconds)
18:09:18.529: This is the item number 7 (I've waited for acquire for 0.499185 seconds)
18:09:19.034: This is the item number 8 (I've waited for acquire for 0.496844 seconds)
18:09:19.527: This is the item number 9 (I've waited for acquire for 0.492872 seconds)

That’s it! Get the source code
Source code for this demo is on my github: https://github.com/yacekmm/looksok/tree/RateLimiterDemo/Guava/RateLimiter

Advertisements

Actions

Information

Give Your feedback:

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: