How to start a thread after specified time delay in java
Asked Answered
K

5

34

I have called a method in ServletContextListener as thread ..Now as per my need i have to delay the thread for 1 minutes and then start executing the method called in the thread but i am not able to do that as i am very new in this...

Here is my code ...

public class Startup implements ServletContextListener {

@Override
public void contextDestroyed(ServletContextEvent sce) {
}

public void contextInitialized(ServletContextEvent sce) {
    // Do your startup work here
    System.out.println("Started....");
    //captureCDRProcess();
    new Thread(new Runnable() {

        @Override
        public void run() {

            captureCDRProcess();
        }
    }).start();

}

Please help me .. Thanks in advance..

Kryska answered 15/11, 2013 at 10:46 Comment(1)
Possible duplicate of java: run a function after a specific number of secondsSalivate
R
68

To do this properly, you need to use a ScheduledThreadPoolExecutor and use the function schedule like this:

final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(NUM_THREADS);
executor.schedule(new Runnable() {
  @Override
  public void run() {
    captureCDRProcess();
  }
}, 1, TimeUnit.MINUTES);

Thread.sleep is not the way to go, because it does not guarantee that it wakes up after a minute. Depending on the OS and the background tasks, it could be 60 seconds, 62 seconds or 3 hours, while the scheduler above actually uses the correct OS implementation for scheduling and is therefore much more accurate.

In addition this scheduler allows several other flexible ways to schedule tasks like at a fixed rate or fixed delay.

Edit: Same solution using the new Java8 Lamda syntax:

final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(NUM_THREADS);
executor.schedule(() -> captureCDRProcess(), 1, TimeUnit.MINUTES);
Renwick answered 15/11, 2013 at 11:9 Comment(4)
To clarify for other readers, it is that 1 and TimeUnit.MINUTES at the end that controls the delay before the new thread is launched.Mariner
What is NUM_THREADS here ,,is it an instance?Knobloch
@Knobloch - it is corePoolSize - the number of threads to keep in the pool, even if they are idle. See docs.oracle.com/javase/7/docs/api/java/util/concurrent/…Garmon
I like this example: mkyong.com/java/java-scheduledexecutorservice-examplesTraffic
B
11

Or you can delay creating the thread with Timer and TimerTask:

public void contextInitialized() {
    // Do your startup work here
    System.out.println("Started....");

    Timer timer = new Timer();

    TimerTask delayedThreadStartTask = new TimerTask() {
        @Override
        public void run() {

            //captureCDRProcess();
            //moved to TimerTask
            new Thread(new Runnable() {
                @Override
                public void run() {

                    captureCDRProcess();
                }
            }).start();
        }
    };

    timer.schedule(delayedThreadStartTask, 60 * 1000); //1 minute
}
Bates answered 15/11, 2013 at 10:58 Comment(2)
Add some explinations, doesn't timerTask execute in a loop?Giron
From my experience Timer creates several threads, which makes it a bit heavy for just a delayed execution.Salivate
S
3

Have a look at Thread.sleep(). Maybe add it to the new thread's run method, so that it sleeps the needed time before doing any meaningful work.

Scleroma answered 15/11, 2013 at 10:48 Comment(0)
G
2

You can start thread and inside the thread use sleep method for one minute.

Grindstone answered 15/11, 2013 at 10:47 Comment(3)
That is what I would do, rather than delaying the creating thread.Trampoline
@Preetygeek Martin is not the OP :)Randee
Thread sleep is unsafe as it does not guarantee that the thread wakes up after a minute.Renwick
S
0

ScheduledThreadPoolExecutor has this ability, but it's quite heavyweight.

Here's a simple implementation with a test (signature close to Android's Handler.postDelayed()):

public class JavaUtil {
    public static void postDelayed(final Runnable runnable, final long delayMillis) {
        final long requested = System.currentTimeMillis();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        long leftToSleep = requested + delayMillis - System.currentTimeMillis();
                        if (leftToSleep > 0) {
                            Thread.sleep(leftToSleep);
                        }
                        break;
                    } catch (InterruptedException ignored) {
                    }
                }
                runnable.run();
            }
        }).start();
    }
}

Test:

@Test
public void testRunsOnlyOnce() throws InterruptedException {
    long delay = 100;
    int num = 0;
    final AtomicInteger numAtomic = new AtomicInteger(num);
    JavaUtil.postDelayed(new Runnable() {
        @Override
        public void run() {
            numAtomic.incrementAndGet();
        }
    }, delay);
    Assert.assertEquals(num, numAtomic.get());
    Thread.sleep(delay + 10);
    Assert.assertEquals(num + 1, numAtomic.get());
    Thread.sleep(delay * 2);
    Assert.assertEquals(num + 1, numAtomic.get());
}
Salivate answered 13/11, 2016 at 17:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.