1

I'm working on a web application which needs to perform some long running tasks (tasks that take around 20 minutes to complete).

I want them to run on a parallel thread, so that the user can keep working on something else within the web app while the task is running.

Assume this is the class that performs the task

public class TaskPerformer {

    public void performTask(String[] taskParameters){

        // Long running task

    }

}

I have created a thread class like this

public class TaskThread extends Thread {
    private TaskPerformer performer = new TaskPerformer();
    private String threadName;

    public TaskThread(String name){
        this.threadName = name;
    }

    public void run(){
        String[] params = {"Param1","Param2","Param3"};
        this.performer.performTask(params); // This might take 15-20 mins to complete
        System.out.println("Task completed successfully");
    }
}

Now, in my web app, I create a new thread based on this one, and start it, so that the task happens on a separate thread. This allows my user to carry on with some of his other works on my webapp.

Now, I would like to add a button on my GUI to pause and stop this task.

Being new to multi threading, I did some reading and found out that I can't use suspend() or resume() as they're depreciated. So in my other trial-and-error sessions, I tried to implement a simple pauseable thread like the one below:

public void run(){
    for(int i=10;i>0;i--){
        checkForPaused();
        System.out.println(this.threadName + " -- Counter -- " + i);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

I implemented the checkForPaused() method to check for a boolean flag to check if I need to pause a thread, and do a wait() on a static variable as long as the boolean is not changed.

(I got this idea from this post How to Pause and Resume a Thread in Java from another Thread)

But, the pitfall in the solution, is that I have to call the checkForPaused() in every iteration of my loop. Which means, that there is no way I can pause the long task I'm going to start, because I do that only once in a thread.

Can anyone suggest an idea how I can implement this?

Community
  • 1
  • 1
Sriram Sridharan
  • 720
  • 18
  • 43
  • You can start a background process which you can kill at any time. – Peter Lawrey Aug 21 '15 at 12:29
  • Put a public volatile boolean on the thread called pause. In your task repeatedly check the paused boolean and sleep if paused. – bhspencer Aug 21 '15 at 12:33
  • @PeterLawrey Thanks, but could you explain how I can do that? any starting point of reference? – Sriram Sridharan Aug 21 '15 at 12:46
  • @bhspencer Thanks, but that's exactly my problem. I don't want to keep checking a flag at regular intervals because I'll have to do that across packages and classes. Is there any other alternative? – Sriram Sridharan Aug 21 '15 at 12:47

2 Answers2

2

If you don't call checkForPaused repeatedly, there is no way to pause your thread from the outside, without risking inconsistent behaviour. The reason why suspend() and resume() are deprecated is because the thread could be stopped at a moment where the data is in an inconsistent state, so the only way to do this right, is to notify the thread that it should be paused. But how and when this happens should only be implemented in the thread itself (because only the thread knows when the data is in a consistent state).

A possible helper class:

public class Helper {
    private volatile boolean flag;

    public synchronized void pause() {
        flag = true;
    }

    public synchronized void isPaused() {
        while(flag) {
            try {
                wait();
            } catch (InterruptedException e) {
                // Set to false, so the thread can be interrupted (!= paused)
                flag = false;
            }
        }
    }

    public synchronized void continue() {
        flag = false;
        notify();
    }
}

Keep a reference in the object of your worker method and anywhere where you need to pause/unpause the thread. Call isPaused() in your worker method regulary.

Lasse Meyer
  • 1,429
  • 18
  • 38
  • What you are telling means in my performTask() method, do I have to keep checking a flag at certain intervals in order to pause the tread. If my understanding is correct, then how to I get the value of the flag to my TaskPerformer object, since it's already initialized and I have a method that's executing currently. Question number two would be, is there no other way??? How do other programs do that ? say IDEs like Eclipse for instance. – Sriram Sridharan Aug 21 '15 at 12:45
  • Or, if I can handle problems that I face when my thread pauses when data is at an inconsistent state, can I still use depreciated methods? – Sriram Sridharan Aug 21 '15 at 13:08
  • 1. If there is a way around the deprecated method, don't use them. 2. Just use a constructor parameter to give your TaskPerformer the reference to the Helper-reference. – Lasse Meyer Aug 21 '15 at 15:51
0

You can use

ProcessBuilder ps = new ProcessBuilder(...)
ps.start();

and when you have given up on it

ps.destroy();

Further reading

https://stackoverflow.com/a/22362599/57695

How to Terminate a Process Normally Created using ProcessBuilder

Community
  • 1
  • 1
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130