How to make a ScheduledExecutorService launch a new task while the previous one is not yet finished?

4

I'm implementing a scheduler to run some threads on my system at x time intervals. The big problem is that if thread 1 still has not finished running, a 2 does not start, even its time having arrived.

In the example below I "forced" this error because I was suspicious that this could be happening.

Thread

package backgroundProcesses;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimerTask;

public class MinhaThread implements Runnable {

    @Override
    public void run() {
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        System.out.println("FOI, COMEÇOOU A THREAD: " +  sdf.format(cal.getTime()));
        int i = 0;
        while(i < 1000000000) {
            int a = 1;
        }

        System.out.println("CHEGOU AO FIM");
    }

}

Executor

package backgroundProcesses;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class ExecutorThreads implements ServletContextListener {

     private ScheduledExecutorService scheduler;


     @Override
    public void contextInitialized(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        scheduler = Executors.newScheduledThreadPool(4);
        scheduler.scheduleAtFixedRate(new MinhaThread(), 0, 10, TimeUnit.SECONDS); 
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        scheduler.shutdownNow();
    }



}

I'm running the application on a simple Tomcat, I do not use TomcatEE.

Desired Outcome:

  

When you start the program, the first thread will be created. 10 seconds later, even though the first thread is still in the loop, the second thread is also created and starts rolling.

    
asked by anonymous 05.07.2018 / 21:34

2 answers

5

This is not possible and this is highlighted in documentation .

  

If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.

     

If the task runs longer than its period, subsequent runs can start later, but will not run simultaneously.

A possible approach (1) is the scheduler use another executor to perform the "time-consuming / long" task.

@WebListener
public class Executor implements ServletContextListener {

    private ScheduledExecutorService scheduler;
    private ExecutorService executorService;

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        // TODO Auto-generated method stub

        executorService = Executors.newCachedThreadPool();
        scheduler = Executors.newScheduledThreadPool(4);

        scheduler.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                executorService.submit(new MinhaThread());
            }
        }, 0, 10, TimeUnit.SECONDS);

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        scheduler.shutdownNow();
    }    

}

When the scheduler triggers, the MinhaThread task is executed using an Executor of the "type" CachedThreadPool.

newCachedThreadPool () creates a Executor using a thread pool . New threads are created if needed or previously created are used if available.

Note: The class name MinhaThread should be MinhaTarefa or MyTask .

(1) More or less what CarlosHeuberger suggested in your comment .     

13.07.2018 / 13:00
0

The solution proposed by @Carlos Heuberger really worked:

Main thread

package backgroundProcesses;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimerTask;

public class MinhaThread implements Runnable {

    @Override
    public void run() {
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        System.out.println("FOI, COMEÇOOU A THREAD: " +  sdf.format(cal.getTime()));
        int i = 0;
        while(i < 1000000000) {
            int a = 1;
        }

        System.out.println("CHEGOU AO FIM");
    }

}

Secondary Thread

package backgroundProcesses;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class OutraThread implements Runnable {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        System.out.println("ENTROU NA THREAD SECUNDARIA");
        new Thread(new MinhaThread()).start();

    }

}

Executor

package backgroundProcesses;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;



@WebListener
public class Executor implements ServletContextListener {

     private ScheduledExecutorService scheduler;


     @Override
    public void contextInitialized(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        scheduler = Executors.newScheduledThreadPool(4);
        scheduler.scheduleAtFixedRate(new OutraThread(), 0, 10, TimeUnit.SECONDS); //roda a qualidade a cada 5 minutos.
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        scheduler.shutdownNow();
    }



}

Console:

ENTROU NA THREAD SECUNDARIA
FOI, COMEÇOOU A THREAD: 11:54:33
ENTROU NA THREAD SECUNDARIA
FOI, COMEÇOOU A THREAD: 11:54:43
ENTROU NA THREAD SECUNDARIA
FOI, COMEÇOOU A THREAD: 11:54:53
ENTROU NA THREAD SECUNDARIA
FOI, COMEÇOOU A THREAD: 11:55:03
ENTROU NA THREAD SECUNDARIA
FOI, COMEÇOOU A THREAD: 11:55:13
ENTROU NA THREAD SECUNDARIA
FOI, COMEÇOOU A THREAD: 11:55:23

I'm going to leave the question open to see if any other solution will come up, but for now I'll implement that here.

    
06.07.2018 / 15:57