2

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

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

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

但我不想在每个 JobImplementaionClass 的每个 for 循环中实现这一点。

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

就像是

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 循环并且有可能中断而不必关心它。

有谁知道如何实际实现这一点?这可能吗?

4

5 回答 5

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

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

于 2013-05-23T10:18:57.503 回答
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 来避免任何并发问题

于 2013-05-23T10:40:36.463 回答
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
    }
}


}

实现子类去

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

实现子类现在使用 doLoop(Callable, Runnable) 方法。doLoop 方法会无限运行。Callable 计算中断条件。runnable 执行循环体的实际代码。然后 doLoop 检查 isInterrupted-flag 是否为真并在这种情况下中断。

doLoop 中的 sleep 仅用于测试。如果我将睡眠放入可运行文件中,它似乎不起作用,但是 pffft。只是测试代码......内部类中断器也是如此。您应该想象,中断将完全来自其他地方。

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

于 2013-05-30T08:52:49.350 回答
0

你可以把for-loop 变成while-loop

public void execute() {
    int i = 0;
    while (!isInterrupted() && i < 10) {
        // do something with i
        i++;
    }
}
于 2013-05-23T10:17:36.883 回答
0

我建议使用只包含一次迭代的任务Executors.singleThreadedExecutorsubmit在您的控制类中,您只需确保提交任务的次数正确,只需关闭ExecutorService.

于 2013-05-23T10:17:50.700 回答