如何正确处理可能未传递给客户端代码的InterruptedException?

Etk*_*tki 5 java interrupted-exception

我偶然发现了一个我必须处理的情况InterruptedException,但不能将它向上传递,并且不要觉得我的代码应该被允许吞下它.确切地说,我正在进行分布式锁实现,并且支持服务的请求可能会中断甚至超时 - 当然,这java.util.concurrent.Lock并不能解释这种情况,也不允许我吐出InterruptedException.我挣扎写非投掷正确实施lock(),tryLock()unlock()方法.

所以,问题是 - 处理这种情况的正确策略是什么?从目前的角度来看,我只看到三个选项(我感觉每个人都有气味):

  1. 忽略lock/ tryLock/ unlock方法中的中断异常,重试/返回false /假设即使请求没有到达目的地,TTL最终也会解锁记录.这显然不是最好的解决方案,因为它希望一切都好,而不是处理问题.
  2. 包裹RuntimeException继承人.这似乎也是一个非常糟糕的解决方案,因为客户端代码必须使用具体的实现而不是原始接口,并且未经检查的异常当然不是为了这样的目的.
  3. 使用 Thread.currentThread().interrupt()呼叫.我不喜欢这种方式,因为它基本上告诉线程处理它自己的中断,而不是传递关于呼叫被中断的通知; 另外,据我所知,如果没有外部轮询,它最终会产生线程,但不会立即处理中断,可能是在另一个地方.

(而且,当然有一个选项允许客户端代码配置所需的行为,但这仍然没有为我提供一个非常好的解决方案)

有没有比我所描述的更好的方式?如果不是,哪一个应优先于其他?

MS *_*nth 5

让我讨论您的每一个可用选项。

  1. 忽略中断的异常

这是错误的。当您实现其他用户将依赖的库之类的东西时,吞下异常永远是不对的。在这些情况下,吞下异常永远不会谨慎,除非您将其作为不同的异常进行传播,从而为客户端提供更有意义的信息。AnInterruptedException基本上是取消您的线程的请求,并且无论稍后是否解锁锁,都不应该从客户端抑制此信息。客户端需要知道有人想要停止该线程正在执行的工作单元。

  1. 包裹起来 RuntimeException

不。这也是错误的,原因与上述完全相同。传播 an 的原因InterruptedException是让客户端知道已发出取消正在执行的线程的请求,因此将其包装在 a 中RuntimeException是错误的,因为此信息丢失了。

  1. 使用/强制Thread.currentThread().interrupt()调用

这可能是对的,也可能是错的,具体取决于用例。问问自己是否可以传播 InterruptedException。

  • 如果可以这样做(但不是在你的情况下),那么你可以声明你的方法抛出InterruptedException并让上面的调用者担心需要做什么。当您调用operation()抛出 an的方法(例如)时,通常会出现这种情况,InterruptedException除非此调用完成,否则您将无法继续进行。假设operation()throwsInterruptedException那么除了传播此异常之外,您无能为力。所以你不应该捕捉异常。在这种情况下,只需声明您的方法抛出InterruptedException就完成了

  • 如果这样做不好,那么处理它的正确方法是强制interrupt()调用。使用它可以抑制异常,但您仍然可以让客户端选择检查标志以查看是否发出中断请求。你是对的。这需要客户端轮询而不是处理中断。但这并没有错。如果您不希望客户端进行轮询,那么传播异常将是更好的选择。但这并不总是可行的,您的示例就是这样的一个用例。并且在很多情况下,执行线程即使被中断也可以返回一些有意义的信息。所以在这种情况下,异常被抑制,但仍然可以通过调用在上面传递有终止请求的信息interrupt()方法。因此,客户端可以只使用从部分计算返回的结果,也可以根据用例轮询检查是否设置了中断标志。因此,您通过这样做为客户提供了更大的灵活性。