ScheduledExecutorService - a program that does not end with a single action

I have a scheduled task in my program that closes a frame after a certain amount of time. However, after the task is completed, the program continues to run as if ScheduledExecutorService

it were still running on a different thread.

This is an important part of my code:

int delay = 1000;

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.schedule(() -> {

    System.out.println("executed");
    getWindow().closeWindow();
    // ex.shutdown();

}, delay, TimeUnit.MILLISECONDS);

      

Here, the task is executed after a 1 second delay, "executed" is printed once, the frame is closed, and the program continues to run even after this code. If I uncomment ex.shutdownNow();

, the program succeeds. However, I cannot figure out why this is happening. I also couldn't find anything from the rest of the internet.

MCVE:

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

public class Main {

    public static void main(String[] args) {
        int delay = 1000;

        ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
        ex.schedule(() -> {

            System.out.println("executed");
            // ex.shutdown();

        }, delay, TimeUnit.MILLISECONDS);
    }

}

      


Lambda may have given it away, but this is really Java 8.

Why doesn't the program stop after completing the task?

+3


source to share


5 answers


The thread pool ScheduledExecutorService

returned Executors#newSingleThreadScheduledExecutor()

is using non-daemon threads. As long as you don't close the thread pool, they are still waiting. The JVM does not end until the thread exists.

You can use the overloaded Executors#newSingleThreadScheduledExecutor(ThreadFactory)

and provide your own implementation ThreadFactory

that creates the daemon threads. Note that this may cause your task to not even work because the JVM will exit before the scheduled time of the task.



Do what you find and close. Please note that you should always close it somewhere in a safe place where the operation cannot fail.

+8


source


The Java virtual machine runs until all threads that are not daemon threads have died . And Executors.defaultThreadFactory()

creates each new thread as a thread without a daemon. However, there is an overload Executors.newSingleThreadScheduledExecutor();

that takes a parameter ThreadFactory

as a parameter if you want to venture in that direction.



    public static void main(String[] args) {
        int delay = 1000;

        class DaemonFactory implements ThreadFactory
        {
            @Override
            public Thread newThread(Runnable r)
            {
                Thread t = new Thread(r);
                t.setDaemon(true);
                return t;
            }
        }

        ThreadFactory tf = new DaemonFactory();
        ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor(tf);
        ex.schedule(() -> {
            System.out.println("executed");
        }, delay, TimeUnit.MILLISECONDS);
    }

      

+2


source


I would have acted completely differently. You indicate:

I have a scheduled task in my program that closes a frame after a certain amount of time.

Why not use a Swing timer for this instead, since it was built to work well with the Swing event flow?

new Timer(1000, new ActionListener() {

    public void actionPerformed(ActionEvent e) {
        ((Timer) e.getSource()).stop();
        someWindow.dispose();        
    }

}).start();

      

0


source


You can call shutdown from the ScheduledExecutorService, as it will wait for the thread to execute and then terminate the thread pool. As you can see in the Javadoc: "Initiates an orderly shutdown in which previously assigned tasks are executed, but no new tasks will be accepted. The call has no additional effect if it is already disabled."

Example:

...
scheduledExecutorService.schedule(runnable, delay, TimeUnit.MILLISECONDS);
scheduledExecutorService.shutdown();
...

      

0


source


I start the scheduler from onCreate () and stop it in onDestroy () to stop the scheduler service.

public MyActivity extends Activity
{
ScheduledExecutorService scheduledExecutorService;
    ScheduledFuture<?> scheduledFuture;
    private int apiThreshold = 10;//seconds


onCreate()
{
    startScheduler();
 }

onDestroy()
{
    if (scheduledFuture != null) 
{ 
 stopScheduler(); 
}
 shutDownService();
  super.onDestroy();
 }

 public void startScheduler() {
        Debug.e(TAG, "inside start scheduler");
        scheduledExecutorService = Executors.newScheduledThreadPool(1);

        scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                // call method to do your task/perform your repeated task
            }
        }, 4, apiThreshold, TimeUnit.SECONDS);
    }


public void shutDownService()
    {
        if (scheduledExecutorService != null) {
            Log.e("test,"in shutDown service close if not null");
            scheduledExecutorService.shutdownNow(); // shutdown will allow the final iteration to finish
            // executing where shutdownNow() will kill it immediately

            Log.e("test,"is service shutdown(true/false)=="+scheduledExecutorService.isShutdown());
        }
    }

 }

      

0


source







All Articles