可中断的for循环

时间:2013-05-23 10:12:35

标签: java loops interrupt

我目前正在尝试实施可中断的工作。 一般的工作看起来像这样

public abstract class Job
{
    private boolean interruptFlag;

    public boolean isinterrupted()
    {
        return interruptFlag;
    }

    public void interrupt()
    {
        interruptFlag = true;
    }

    public abstract void execute();

}

public class JobImplementation extends Job
{
    public void execute
    {
        for (int i = 0; i < 10; i++)
        {
            doSomethingWithI(i);
            if (interruptedFlag())
            {
                break;
            }
        }
    }
}

当某个控制器调用interrupt() - 方法时,我想中断执行体中的for循环。

但是我不想在每个JobImplementaionClass中的每个for循环中实现它。

我想做的是类似抽象Job类中的方法,它将执行代码和条件作为参数获取。

这样的东西
protected void doFor(conditionCode, executionCode)
{
    for (conditionCode)
    {
         executeCode();
         if (isInterrupted())
             break;
    }
}

并且JobImplementation类不会使用正常的for循环,而是:

public void execute()
{
    doFor({int i = 0; i < 10; i++}, {doSomethingWithI(i)})
}

这样我试图隐藏实际JobImplementation中的控制细节。 当我编写一个新的JobImplementation时,我可以使用这个doFor-loop并且可以在不必关心的情况下中断。

有没有人知道如何实际实现这个?这可能吗?

5 个答案:

答案 0 :(得分:1)

public abstract class LoopJob extends Job {
    private int iterations;

    public LoopJob(int iterations) {
        this.iterations = iterations;
    }

    @Override public void execute() {
        for (int i = 0; i < iterations && !isInterrupted(); ++i) {
            executeIteration(i);
        }
    }

    protected abstract void executeIteration(int i);
}

这样的东西?如果你真的需要这种灵活性,可以通过将初始化器,条件和增量器放入其他抽象方法,将循环变量转换为派生类的成员来使其更灵活。

答案 1 :(得分:0)

您可以将for - 循环转换为while - 循环

public void execute() {
    int i = 0;
    while (!isInterrupted() && i < 10) {
        // do something with i
        i++;
    }
}

答案 2 :(得分:0)

我建议使用Executors.singleThreadedExecutor,其中submit任务只包含一次迭代。在您的控制类中,您只需确保将任务提交正确的次数,然后只需关闭ExecutorService即可处理中断。

答案 3 :(得分:0)

以前的答案没有考虑过一个重要的事情:并发

你应该使用像AtomicBoolean这样的东西来控制中断的标志(因为,此时,当某个线程'中断'你的循环时,你的循环代码可能永远不会得到新的中断状态。)

我的建议是使用以下代码:

public abstract class Job
{
    private final AtomicBoolean interruptFlag = new AtomicBoolean(false);
    private final int loopCount;

    protected Job(final int loopCount) {
        this.loopCount = loopCount;
    }

    public final boolean isinterrupted()
    {
        return interruptFlag.get();
    }

    public final void interrupt()
    {
        interruptFlag.set(true);
    }

    public final void execute() {
        for (int i = 0; i < loopCount && !checkInterrupted(); i++) {
           doSomethingWithI(i);
        }
    }

    protected abstract boolean checkInterrupted();

    protected abstract void doSomethingWithI(int i);

}

public class InterruptableJob extends Job
{
    public InterruptableJob () {
         super(10);
    }

    protected final boolean checkInterrupted() {
         return isInterrupted();
    }

    protected final void doSomethingWithI(final int i) {
          .... ;
    }
}

我对双重访问isInterrupted(通过使用checkInterrupted())的推理是这样的,当你有一个你不想打断它的类时,你的循环实现可以是:

    protected final boolean checkInterrupted() {
         return false;
    }

并且通过上面的实现,Java运行时将完全忽略测试,并且不会对性能产生影响。

请注意我如何使用AtomicBoolean来避免任何并发问题

答案 4 :(得分:0)

对不起,等了很久。 对于那些仍然感兴趣的人,我现在找到了实施似乎有效的解决方案的时间。

public abstract class Job
{
    AtomicBoolean isInterrupted = new AtomicBoolean(false);

    public boolean isinterrupted()
    {
        return interruptFlag;
    }

    public void interrupt()
    {
        isInterrupted.set(true);
    }

    public abstract void execute();

    public void doLoop(Callable<Boolean> callable, Runnable runnable) 
    {
    try
        {
            while (true)
        {
            ExecutorService executor = Executors.newSingleThreadExecutor();
            Future<Boolean> result = executor.submit(callable);
                if (!result.get())
                break;
                executor.submit(runnable);
            if (isInterrupted.get())
                break;

                        // TestCode. simulates some serious code given 
                        // by the the runnable
               try
               {
                   Thread.sleep(1000);
               } 
                               catch (InterruptedException e)
               {
                           // do Something
               }
        }
    }
    catch (InterruptedException e)
    {
            // do Something
    } 
    catch (ExecutionException e)
    {
            // do Something
    }
}


}

实施SubClass

public class JobImplementation extends Job
{
public void execute()
{
    Thread interruptor= new Thread(new Interrupter(this));
    interruptor.start();
    final Iterator<String> it = collection.iterator();
    doLoop(new Callable<Boolean>() 
           {
               public Boolean call() throws Exception 
               {
                   return it.hasNext();
               }}, 
           new Runnable() 
           {
               public void run()
               {
                   System.out.println(it.next());
               }
           });
}


public class Interrupter implements Runnable 
    {
        LoopUserClass user;
        public Interrupter(LoopUserClass user)
        {
            this.user = user;
        }

        public void run() 
        {
            try
            {
                Thread.sleep(5000);
            } 
            catch (InterruptedException e)
            {
                // do Something
            }
            user.interrupt();
        }
}

    public static void main(String[] args)
    {
        LoopUserClass user = new LoopUserClass();       
        for (int i = 0; i < 10; i++)
        {
            user.collection.add("testString" + i);
        }
        user.execute();
    }
}

实现subClass现在使用doLoop(Callable,Runnable)-method。 doLoop方法运行无穷无尽。 Callable计算中断条件。 runnable执行loop-body的实际代码。 然后doLoop检查isInterrupted-flag是否为真,并在这种情况下中断。

doLoop中的睡眠仅用于测试。如果我将睡眠放入可运行的,但是pffft,它似乎不起作用。只是testCode ... 对于内部类中断器也是如此。你应该想象,中断将完全来自某个地方。

这个概念看起来有点难看,因为doLoop的用户必须创建Callable和Runnable-Objects。在用java实现闭包之前,这可能不会改变。