【问题标题】:MultiThreading Java - Pausing a long running tasks from a Web ApplicationMultiThreading Java - 暂停来自 Web 应用程序的长时间运行的任务
【发布时间】:2015-08-21 12:23:50
【问题描述】:

我正在开发一个需要执行一些长时间运行的任务(大约需要 20 分钟才能完成的任务)的 Web 应用程序。

我希望它们在并行线程上运行,以便用户可以在任务运行时继续处理 Web 应用程序中的其他内容。

假设这是执行任务的类

public class TaskPerformer {

    public void performTask(String[] taskParameters){

        // Long running task

    }

}

我已经创建了一个这样的线程类

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

现在,在我的网络应用程序中,我基于这个创建一个新线程并启动它,以便任务在单独的线程上发生。这允许我的用户在我的 web 应用上继续他的一些其他工作。

现在,我想在我的 GUI 上添加一个按钮来暂停和停止此任务。

作为多线程的新手,我做了一些阅读,发现我不能使用suspend() 或resume(),因为它们已被贬值。因此,在我的其他试错会话中,我尝试实现一个简单的可暂停线程,如下所示:

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

我实现了 checkForPaused() 方法来检查一个布尔标志来检查我是否需要暂停一个线程,并在一个静态变量上执行一个 wait(),只要布尔值没有改变。

(我从这篇帖子How to Pause and Resume a Thread in Java from another Thread得到这个想法)

但是,解决方案的缺陷是我必须在循环的每次迭代中调用 checkForPaused()。这意味着,我无法暂停即将开始的长任务,因为我在一个线程中只执行一次。

任何人都可以建议我如何实现这一点吗?

【问题讨论】:

  • 您可以启动一个可以随时终止的后台进程。
  • 在名为 pause 的线程上放置一个公共 volatile 布尔值。在您的任务中反复检查暂停的布尔值,如果暂停则休眠。
  • @PeterLawrey 谢谢,但你能解释一下我该怎么做吗?有什么参考起点吗?
  • @bhspencer 谢谢,但这正是我的问题。我不想定期检查标志,因为我必须跨包和类进行检查。还有其他选择吗?

标签: java multithreading


【解决方案1】:

如果您不重复调用 checkForPaused,则无法从外部暂停线程,而不会冒不一致的行为。不推荐使用suspend() 和resume() 的原因是因为线程可能会在数据处于不一致状态的时刻停止,所以做到这一点的唯一方法是通知线程它应该被暂停.但是这种情况如何以及何时发生只能在线程本身中实现(因为只有线程知道数据何时处于一致状态)。

一个可能的辅助类:

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

在您的工作方法的对象以及您需要暂停/取消暂停线程的任何地方保留一个引用。定期在您的工作方法中调用 isPaused()。

【讨论】:

  • 你所说的意思是在我的 performTask() 方法中,我是否必须每隔一定时间检查一个标志才能暂停胎面。如果我的理解是正确的,那么如何将标志的值传递给我的 TaskPerformer 对象,因为它已经初始化并且我有一个当前正在执行的方法。第二个问题是,有没有其他办法???其他程序如何做到这一点?比如说像 Eclipse 这样的 IDE。
  • 或者,如果我可以处理当我的线程在数据处于不一致状态时暂停时遇到的问题,我还可以使用折旧的方法吗?
  • 1.如果有办法绕过已弃用的方法,请不要使用它们。 2. 只需使用构造函数参数为您的 TaskPerformer 提供对 Helper-reference 的引用。
【解决方案2】:

你可以使用

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

当你放弃它时

ps.destroy();

进一步阅读

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

How to Terminate a Process Normally Created using ProcessBuilder

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    • 2016-10-07
    • 2018-09-24
    • 1970-01-01
    相关资源
    最近更新 更多