Thread.suspend()和.resume()的替代方案

时间:2015-03-08 01:18:08

标签: java multithreading

我有一大段代码不是循环,只是一个发生一次但需要一些时间的命令列表。我需要它根据更改的布尔值在任何点暂停或终止它。我可以使用不同的线程来暂停,恢复和停止此代码,但这些方法已被弃用,所以我想避免使用它们。我可以检查每行代码之间的布尔值,但我希望有一个更优雅的解决方案。有没有办法做到这一点?

7 个答案:

答案 0 :(得分:5)

  

我可以检查每行代码之间的布尔值,但我希望有一个更优雅的解决方案。有没有办法做到这一点?

不幸的是,没有。

要替换暂停/恢复,您真正需要的是一个线程“暂停”另一个线程,而不涉及第二个线程的代码。

这不可能像目前规范和实现的那样在Java中安全地进行。

不推荐使用的Thread方法是一个线程杀死,停止/暂停,恢复另一个线程的唯一方法......如果另一个线程没有主动协作。它们被弃用了,因为(简而言之)在任何当前的主流JVM 1 中,无法安全地实现这种控制。

您可以做的最好的事情是将暂停/恢复逻辑包装在第二个线程在适当的位置调用的方法中。 (这可能应该使用wait / notify ...或等效的......来处理恢复。但是wait / notify 本身并没有解决你暂停/恢复非合作线程的明确要求。)


1 - 你需要像Isolates API这样的东西。已经尝试在研究项目中实现它,但AFAIK Isolates从未在生产JVM中实现。

答案 1 :(得分:2)

有关于为什么Thread.stop()Thread.pause()Thread.resume()被弃用的优秀文档:

Java Thread Primitive Deprecation

使用Thread.pause()Thread.resume()解释了wait / notify的替代方案。

答案 2 :(得分:1)

您可以使用wait / notify作为暂停/恢复的替代方法。您可以设置标志,通知并从通知的线程中抛出异常

,而不是停止

答案 3 :(得分:1)

处理中断线程的正确方法(在这种情况下,暂停或停止它)当然是Thread#interrupt()。它的设计使您可以定义线程可以被中断的安全点,这对您来说自然就是每个任务之间的点。因此,为了避免必须在每个任务之间手动检查变量,并且能够轻松地从中断的位置恢复,您可以将任务存储为Runnable的列表,并记住您在列表中的位置当你离开的时候,就像这样:

public class Foo {
    public static void runTask(Runnable task) throws InterruptedException {
        task.run();
        if (Thread.interrupted()) throw new InterruptedException();
    }
    Runnable[] frobnicateTasks = new Runnable[] {
        () -> { System.out.println("task1"); },
        () -> { Thread.currentThread().interrupt(); }, //Interrupt self only as example
        () -> { System.out.println("task2"); }
    };
    public int frobnicate() {
        return resumeFrobnicate(0);
    }
    public int resumeFrobnicate(int taskPos) {
        try {
            while (taskPos < frobnicateTasks.length)
                runTask(frobnicateTasks[taskPos++]);
        } catch (InterruptedException ex) {
        }
        if (taskPos == frobnicateTasks.length) {
            return -1; //done
        }
        return taskPos;
    }
    public static void main(String[] args) {
        Foo foo = new Foo();
        int progress = foo.frobnicate();
        while (progress != -1) {
            System.out.println("Paused");
            progress = foo.resumeFrobnicate(progress);
        }
        System.out.println("Done");
    }
}
-->
task1
Paused
task2
Done

答案 4 :(得分:1)

我知道如何使用AspectJ来做到这一点。我在下面概述的解决方案将允许您暂停/恢复另一个线程。在您调用暂停例程后,此暂停仅对目标方法内部的下一个方法调用生效。这将 not 在目标方法的每行代码之后需要布尔检查。我正在使用wait / notify来执行此操作。

我在下面的例子中使用Spring。

首先,将目标方法包装在Runnable中。

   package com.app.inter.thread.communication.runnables;


    public class TestRunnable implements Runnable{

        public void run() {
            long i=0;
            //For explanatory purposes, I have used an infinite loop below
            //and printed an increasing number

            while(!Thread.interrupted()){
                //someService.action1();
                //someService.action2();
                //....                    
                if(i++%10000000==0)
                    System.out.println("Working "+i);
            }

        }

    }

接下来,您将创建一个可在目标方法中的任何方法调用上有条件调用的方面。

@Aspect
@Component
public class HandlerAspect {

    public static volatile boolean stop=false;
    public static volatile String monitor="";



    @Pointcut("withincode(public void com.app.inter.thread.communication.runnables.TestRunnable.run()) "
            + "&& call(* *.*(*)) "
            + "&& if()")
    public static boolean stopAspect(){
        return stop;
    }
    @Before("stopAspect()") 
    public void beforeAdvice(JoinPoint jp) {
       try {
           System.out.println("Waiting");

           synchronized(monitor){
               monitor.wait();
           }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        stop=false;
    }
}

现在,只要您想暂停线程,只需将stop的值设置为true,反之亦然。

@Service
public class Driver {
    @Autowired
    private HandlerAspect aspect;

    @PostConstruct
    public void init(){
        Scanner scanner = new Scanner(System.in);
        int i=-1;
        TestRunnable runnable = new TestRunnable();
        Thread thread= new Thread(runnable);
        thread.start();
        aspect.monitor="MONITOR";
        while((i=scanner.nextInt())!=0){
            switch(i){
                case 1: 
                    aspect.stop=true;
                    break;      
                case 2:

                    aspect.stop=false;                  
                    synchronized(aspect.monitor){
                        aspect.monitor.notify();
                    }
                    break;  
            }
        }
        // in case the main thread is stopped
        // while the other thread is in wait state
        synchronized(aspect.monitor){
            aspect.monitor.notify();
        }
        thread.interrupt();

    }
}

输出如下:

...
Working 400000001
1Working 410000001
Working 420000001
Working 430000001
Working 440000001
Working 450000001
Working 460000001
Working 470000001
Waiting
2
Working 480000001
Working 490000001
0

工作代码位于https://github.com/zafar142007/InterThreadCommunication

答案 5 :(得分:0)

我不知道为什么没人在这里提到七叶树。您可以偶尔尝试在您的主代码中获取并释放一个字母。在旁边的工作中,您可以触发sephamore获取,因此,如果您不希望整个while循环等待并通知进行,则可以阻止获取主要代码。

答案 6 :(得分:0)

以某种方式,该线程似乎仍然很活跃,所以我要回答我的问题,因为4年的开发经验给了我更多的见解,并且还没有使我对问题的记忆蒙上阴影。

这个问题归结为我正在使用的FRC库,试图使我horn脚使用类似motor.drive(speed, time)的函数,并且会在一段时间内阻塞执行。在除最狭窄的情况以外的所有情况下,这都是不好用的功能,因为很多机器人代码都依赖于结合传感器数据和时间传递来做出决策。

我应该做的是在时间为0或很小的时候调用它,或者找到其他可以无限期驱动电动机的功能,并确保随后将其关闭。然后紧紧地运行该函数,寻找将要转到下一条命令的条件。

我可能应该使用状态机来使代码更易读和易于修改。