3

Below code attempts to get a connection every 5 seconds. The getConnection method returns true or false depending on random double and is for illustrative purposes. The time it takes to get a connection cannot be guaranteed so if fail to initially get connection, wait 5 seconds and try again. Once the connection is attained, then just exit.

Is there better/cleaner method of getting the connection instead of using if statements and Thread.sleep ? It seems wrong (im not sure why) sleeping the running thread for 5 seconds before trying again.

public class TestAlive {

    public static void main(String args[]) {

        while (true) {
            try {
                if (getConnection()) {
                    System.out.println("Got connection, do some work.....");
                    System.exit(0);
                }
                else {
                    System.out.println("No connection, re-trying in 5 seconds");
                    Thread.sleep(5000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static Boolean getConnection() {
        return Math.random() > 0.5;
    }
}
blue-sky
  • 51,962
  • 152
  • 427
  • 752
  • I came across this post while looking answer to your question. It looks like a similar problem and a solution with good design. http://stackoverflow.com/questions/11692595/design-pattern-for-retrying-logic-that-failed Hope it helps. – TheCodingFrog May 26 '15 at 10:57
  • 1
    It looks fine but make sure to propagate interruption vs. swallowing the interuptedexception (unless you have a good reason not to)... – assylias May 26 '15 at 11:08

3 Answers3

2

I think a loop with a Thread.sleep is a good approach, especially if you want to include a maximum number of retries and since rethrowing the InterruptedException is most likely the best way to handle interrupts in a situation like this.

An alternative would be to use a ScheduledExecutorService as follows:

ScheduledExecutorService exec = new ScheduledThreadPoolExecutor(1);

exec.scheduleWithFixedDelay(() -> {
    if (getConnection()) {
        System.out.println("Got connection, do some work.....");
        System.exit(0);  // Or exec.shutdown();
    } else {
        System.out.println("No connection, re-trying in 5 seconds");
    }
}, 0, 5, TimeUnit.SECONDS);

or using Timer:

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    public void run() {
        if (getConnection()) {
            System.out.println("Got connection, do some work.....");
            System.exit(0);  // And/or timer.cancel()
        } else {
            System.out.println("No connection, re-trying in 5 seconds");
        }
    }
}, new Date(), 5000);

If this pattern is used in several places, I'd suggest creating a wrapper that accepts a Runnable (or even better, Callable).

On a related note, this is the exact code I use in one of my projects:

int attempt = 0;
while (true) {
    Log.info("Trying to connect. Attempt " + (++attempt) + " of " + MAX_CONNECT_ATTEMPTS);
    try {
        return makeConnectionAttempt();
    } catch (IOException ex) {
        Log.error("Connection attempt failed: " + ex.getMessage());
        if (attempt >= MAX_CONNECT_ATTEMPTS) {
            Log.error("Giving up");
            throw new IOException("Could not connect to server", ex);
        }
    }
    Thread.sleep(WAIT_BETWEEN_CONNECT_ATTEMPTS);
}
aioobe
  • 413,195
  • 112
  • 811
  • 826
0

I don't think call Thread.sleep(5000) is wrong in this case, but maybe dangerous in a bigger application, for this purposes, I use CronTriggers of QuartzScheduler and work really smooth.

A CronTrigger with declaration 0/5 * * * * ? will be executed 5 seconds after last triggered process finishes. But there are plenty of configurations applicable.

Jordi Castilla
  • 26,609
  • 8
  • 70
  • 109
0

Using Thread.sleep() is bad practise

use Timer instead

timer = new Timer();

if (timer != null) {
    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {

            try {
                if (getConnection()) {
                    System.out.println("Got connection, do some work.....");
                    timer.cancel();
                    timer.purge();
                    System.exit(0);
                } else {
                    System.out.println("No connection, re-trying in 5 seconds");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, 0, 5000);
Don Chakkappan
  • 7,397
  • 5
  • 44
  • 59
  • A) That article is written for .NET, B) I don't think the arguments they bring up apply here. – aioobe May 26 '15 at 10:54
  • @aioobe Updated the link.Even for Java i don't think Thread.sleep() is good practise – Don Chakkappan May 26 '15 at 10:58
  • 2
    If this is a simple "5 second backoff" mechanism, I would say it doesn't really matter if the hardware interrupt granularity is 15ms or if `Thread.sleep` tends to "undersleep" a couple of milliseconds (which are basically the arguments that the article you link to brings up). – aioobe May 26 '15 at 11:02