Java 停止线程时抛出InterruptedException是否必要?我可以使用其他异常类型吗?

Java 停止线程时抛出InterruptedException是否必要?我可以使用其他异常类型吗?,java,multithreading,Java,Multithreading,我有学生代码的比赛代码。因此,我无法控制学生的代码 我需要为学生的代码调用实现超时(它们在单独的线程中运行)。因此,我检测了他们的代码,并在循环和方法定义之后插入了以下代码: if (Thread.interrupted()) throw new InterruptedException(); 问题是InterruptedException已检查,因此我必须向所有方法添加throws声明,这可能会破坏重写方法的签名 所以我认为我不能抛出中断异常,而是一个未经检查的异常,例如运行时异常。我能做吗

我有学生代码的比赛代码。因此,我无法控制学生的代码

我需要为学生的代码调用实现超时(它们在单独的线程中运行)。因此,我检测了他们的代码,并在循环和方法定义之后插入了以下代码:

if (Thread.interrupted()) throw new InterruptedException();
问题是
InterruptedException
已检查,因此我必须向所有方法添加
throws
声明,这可能会破坏重写方法的签名

所以我认为我不能抛出
中断异常
,而是一个未经检查的异常,例如
运行时异常
。我能做吗?会有什么不同吗


在我的竞赛代码中,我在
执行器服务中启动学生代码,并尝试使用带有超时的
get()
获得结果。

InterruptedException由java规范建议:您可以在此处找到更多信息


InterruptedException是java规范建议的:您可以在这里找到更多信息


如果您想要一个简单的超时,并且不关心代码是否优雅地终止,您可以使用。不鼓励使用stop(),因为不管它当前在做什么,它都会在该线程中抛出ThreadDeatheException。通过注入在每个循环中抛出异常的代码,您所做的基本相同(除了jdk代码正常终止)。因此,在这种特殊情况下,我建议使用stop()

但是,如果您更希望取消选中InterruptedException,那么有一个错误

下面是一个如何使用ScheduledExecutorService停止线程的示例

void runWithHardTimeOut(final Runnable task, long timeout, TimeUnit unit) {

    final Thread[] runner = new Thread[1];
    final AtomicBoolean done = new AtomicBoolean(false);

    Runnable killer = new Runnable() {

        @Override
        public void run() {
            if (!done.get()) {
                while (runner[0] == null);
                if (done.get()) {
                    return;
                } else {
                    runner[0].stop();
                }
            }
        }
    };
    final Runnable r = new Runnable() {

        @Override
        public void run() {
            try {
                runner[0] = Thread.currentThread();
                killerExecutor.schedule(killer, timeout, unit);
                task.run();
                done.set(true);
            } catch (ThreadDeath wrench) {}
        }
    };

    executor.execute(r);
}

如果您想要一个简单的超时,并且不关心代码是否优雅地终止,那么可以使用。不鼓励使用stop(),因为不管它当前在做什么,它都会在该线程中抛出ThreadDeatheException。通过注入在每个循环中抛出异常的代码,您所做的基本相同(除了jdk代码正常终止)。因此,在这种特殊情况下,我建议使用stop()

但是,如果您更希望取消选中InterruptedException,那么有一个错误

下面是一个如何使用ScheduledExecutorService停止线程的示例

void runWithHardTimeOut(final Runnable task, long timeout, TimeUnit unit) {

    final Thread[] runner = new Thread[1];
    final AtomicBoolean done = new AtomicBoolean(false);

    Runnable killer = new Runnable() {

        @Override
        public void run() {
            if (!done.get()) {
                while (runner[0] == null);
                if (done.get()) {
                    return;
                } else {
                    runner[0].stop();
                }
            }
        }
    };
    final Runnable r = new Runnable() {

        @Override
        public void run() {
            try {
                runner[0] = Thread.currentThread();
                killerExecutor.schedule(killer, timeout, unit);
                task.run();
                done.set(true);
            } catch (ThreadDeath wrench) {}
        }
    };

    executor.execute(r);
}

标准
ExecutorService
实现中工作线程的中断状态将在任务完成时被清除,并且为了测试任务是否在完成前被取消(由
Future.isCancelled()
检测到),将忽略该中断状态

因此,您可以安全地抛出未经检查的(“运行时”)异常,而不是
InterruptedException
,并且它不会干扰
ExecutorService
的操作

但是,如果您仍然担心,可以通过重新断言中断状态来保持中断状态:

if (Thread.interrupted()) {
  Thread.currentThread().interrupt();
  throw new IllegalStateException("Time limit exceeded.");
}
或者使用其他无法清除的方法:

if (Thread.currentThread().isInterrupted()) 
  throw new IllegalStateException("Time limit exceeded.");
通常情况下,自定义运行时异常是个坏主意,因为它们可能会导致抽象泄漏,但在这里,用自定义类型代替
IllegalStateException
,可以更清晰地区分超时异常和学生代码引发的运行时异常


更新:只有在正确编写任务以支持中断的情况下,取消使用
ExecutorService
运行的任务才是可靠的,您不能相信学生会这样做

因此,您的选择是:

  • 手动查看源代码,必要时插入中断检测
  • 摆脱ExecutorService
  • ,自己创建工作线程。使用
    stop()
    stop(Throwable)
    方法在超时后终止线程。为了实现真正的健壮性,可以使用诸如ASM之类的字节码工程库来自动分析编译后的插件代码,以查看它是否能够捕获用于停止工作线程的
    Throwable
    (或
    ThreadDeath
    或自定义
    Throwable
  • Fork Java进程来运行代理代码,并在超时后终止整个进程

  • 标准
    ExecutorService
    实现中工作线程的中断状态将在任务完成时被清除,并且为了测试任务是否在完成前被取消(由
    Future.isCancelled()
    检测到),将忽略该中断状态

    因此,您可以安全地抛出未经检查的(“运行时”)异常,而不是
    InterruptedException
    ,并且它不会干扰
    ExecutorService
    的操作

    但是,如果您仍然担心,可以通过重新断言中断状态来保持中断状态:

    if (Thread.interrupted()) {
      Thread.currentThread().interrupt();
      throw new IllegalStateException("Time limit exceeded.");
    }
    
    或者使用其他无法清除的方法:

    if (Thread.currentThread().isInterrupted()) 
      throw new IllegalStateException("Time limit exceeded.");
    
    通常情况下,自定义运行时异常是个坏主意,因为它们可能会导致抽象泄漏,但在这里,用自定义类型代替
    IllegalStateException
    ,可以更清晰地区分超时异常和学生代码引发的运行时异常


    更新:只有在正确编写任务以支持中断的情况下,取消使用
    ExecutorService
    运行的任务才是可靠的,您不能相信学生会这样做

    因此,您的选择是:

  • 手动查看源代码,必要时插入中断检测
  • 摆脱ExecutorService,自己创建工作线程。使用
    stop()
    stop(Throwable)
    方法在超时后终止线程。为了实现真正的健壮性,可以使用诸如ASM之类的字节码工程库来自动分析编译后的插件代码,以查看它是否能够捕获用于停止工作线程的
    Throwable
    (或
    ThreadDeath
    或自定义
    Throwable
  • Fork Java进程来运行代理代码,并在超时后终止整个进程
  • 我需要