How to make a Scheduledexecutorservice launch a new task while the previous one has not yet finished?

Asked

Viewed 960 times

5

I am implementing a Scheduler to run some threads on my system at x time intervals. The big problem is that if thread 1 has not yet finished running, 2 does not start, even though its time has come.

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");
    }

}

Executioner

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 don’t use Tomcatee.

Desired Result:

When starting the program, the first thread will be created. 10 seconds later, although the first thread is still in the loop, the second thread is also created and starts to rotate.

  • @Carlosheuberger actually, I want a new instance of the "Minhathread" class. That is, there will be 2 "Minhathread" running at the same time. Maybe I’m wrong there?

  • @Carlosheuberger got it!! Could you give me a brief example of this solution as an answer? At the same time I’ll look here and see if I can solve it too.

  • @Carlosheuberger I’ll try, thank you!

  • @Carlosheuberger I implemented your solution worked, my only concern is: Can creating a thread to call another thread cause me any problems? Or the "other thread" having the sole function of calling "my thread" will make the call and "die", so there is no problem?

2 answers

5


It 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 execution of the task takes longer than your period, subsequent executions may start later, but will not be performed 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 fires, the task MinhaThread is executed using a Cachedthreadpool "type" Executor.

newCachedThreadPool() creates an Executor that uses a thread pool. New threads are created if necessary or are used if available.

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

(1)More or less as suggested by Carlosheuberger at your comment.

  • thank you so much for the reply!! I will test and give a feedback

  • I switched to your solution, it worked accordingly!

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();

    }

}

Executioner

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’ll leave the question open to see if any other solution will come up, but for now I will implement this one.

  • This implementation seems to me to be wrong. It can apparently work because the test does not take place with the time necessary to evidence it (caused by the reason of your question). Note that every 10 seconds OutraThread is defining a scheduleAtFixedRate executing MinhaThread every second.

  • @ramaral I edited the class "Outrathread", this is how I’m doing at the moment, what do you think?

  • I think it will work. However it is preferable to use Executors.newCachedThreadPool(), since it reuses Threads created when available.

  • @ramaral cool! I’ll change my code!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.