我目前正在尝试实施可中断的工作。 一般的工作看起来像这样
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并且可以在不必关心的情况下中断。
有没有人知道如何实际实现这个?这可能吗?
答案 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实现闭包之前,这可能不会改变。