中断正在执行阻塞操作的线程?

huangapple go评论70阅读模式
英文:

Stopping (interrupting) a thread that is running a blocking action?

问题

类似于这个问题,但不同之处在于细节上的差异:https://stackoverflow.com/questions/1820118/interrupting-a-thread-that-waits-on-a-blocking-action

有一个第三方库,我无法控制这个库,这个库有一个方法 pressButtonAndHoldIt(long duration)。这是一个阻塞方法,意味着如果你将 duration 设置为10分钟 - 它将会持续执行10分钟(没有中断)。
我从一个单独的线程中使用这个方法,这样我可以在“按住按钮”的同时做其他事情:

final Future<?> f = Executors.newSingleThreadExecutor().submit(() -> {
  3ptyLibrary.pressButtonAndHoldIt(Duration.ofMinutes(10).toSeconds());
});

var stuff = myOtherStuff();
//在这里,我想要停止在“f”中提交的内容,比如 “f.forceStop()”

通常 myOtherStuff() 大约需要9分钟,但有时可能需要5分钟,所以我想要停止那个阻塞的后台进程。我该如何做到这一点?

请注意,Executors.newSingleThreadExecutor().submit() 只是一个示例:我能够以任何我们可以在Java中创建后台线程的方式创建它(如果这有帮助)。

英文:

Similar to this question, but with difference is in the details: https://stackoverflow.com/questions/1820118/interrupting-a-thread-that-waits-on-a-blocking-action

There is a 3pty library that I don't control, this library has a method pressButtonAndHoldIt(long duration). This is a blocking method, meaning that if you set duration to 10 minutes - it will be doing something for 10 minutes (without interruptions).
I use this method from a separate thread, so I can do something else while "holding the button":

final Future&lt;?&gt; f = Executors.newSingleThreadExecutor().submit(() -&gt; {
  3ptyLibrary.pressButtonAndHoldIt(Duration.ofMinutes(10).toSeconds());
});

var stuff = myOtherStuff();
//here I want to stop what was submitted in &quot;f&quot;, e.g. &quot;f.forceStop()&quot;

Usually myOtherStuff() takes about 9 minutes, but sometimes it could take 5 minutes, so I want to stop that blocking background process. How can I do that?

Note that Executors.newSingleThreadExecutor().submit() is just an example: I am able to create a background thread in any way we can in java (if that helps).

答案1

得分: 3

你唯一能做的事情就是调用thatThreadRef.interrupt();然后祈祷。

interrupt()函数的作用是“提高中断标志”。这只会完成两件事:

  • 所有明确规定要查看该标志的方法,都会查看它:很容易辨认出它们:它们都是那些规定要抛出InterruptedException的方法,比如Thread.sleep。如果在调用这些方法时标志已经被设置,它们会立即返回(通过抛出InterruptedException),根本不会进行休眠。如果你在它们休眠时中断线程,它们将立即退出并抛出异常。
  • 对于其他所有情况,它只是……提高了中断标志。就是这样。

现在,第二件事情并不完全没有用:方法可以在适当的时候自由地检查它,并根据需要采取行动,执行任何看似合适的操作(实际上并没有太多关于你应该做什么的语义标准。只要你返回或者以其他方式中断“某事”)。例如,在大多数操作系统上,但并不是所有操作系统,读取文件(这并未规定抛出InterruptedException)可能会阻塞,如果你中断了它,通常情况下它确实会中止读取操作,导致IOException异常发生。关键是,JVM并不保证这一点(嘿,如果你必须在众多不同的体系结构和操作系统上运行,就必须降低保证的程度)。

所以,你的计划就是祈祷pressButtonAndHoldIt函数会查看这个中断标志。

如果它不会查看,那么你几乎无法直接做任何事情。在这种情况下,如果这个库确实不支持它(既不通过中断,也不通过其他方式),而且你不能编辑源代码或者贡献一个带有更新的拉取请求,那么你最好的选择就是从你的JVM中启动一个全新的JVM(并不容易),然后强制终止它,以尝试“中止”那个阻塞操作。这本身可能不起作用(在这种情况下,这个库相当糟糕,如果它在VM死亡时泄漏资源)。这是一个相当大的措施来解决这个特定的问题,但这是你唯一能用的方法。

英文:

The one and only thing you can do, is call thatThreadRef.interrupt(); and pray.

What interrupt() does is 'raise the interrupt flag'. This accomplishes only two things:

  • All methods that are explicitly specced to look at that will, well, look at that: It's easy to identify em: They are all methods that are specced to throw InterruptedException, such as Thread.sleep. Those methods will IMMEDIATELY return (by throwing InterruptedException) if the flag is up when you call them, never sleeping at all. If you interrupt the thread while they are sleeping, they will exit near immediately by throwing that too.
  • For all other situations it just... raises the interrupt flag. That's all it does.

Now, that second thing is not quite completely useless: A method is free to check it from time to time and act accordingly, doing whatever seems appropriate (there isn't much of an actual semantic standard as to what you ought to do. As long as you return or otherwise break off something). For example, on most OSes, but not all of them, reading a file (which is not specced to throw InterruptedException) can block, and if you interrupt that, generally that does actually work and aborts the read, causing an IOException to occur. The point is, the JVM doesn't guarantee it (hey, if you have to run on a combinatorial explosion of architectures and OSes, you gotta go light on the guarantees).

So, that's your plan: Pray that this pressButtonAndHoldIt thing looks at it.

If it doesn't, there's virtually nothing you can do directly. Your best bet at that point, if truly the library doesn't support it (not via interrupt and not in any other way) and you can't edit the source or contribute a pull request with an update, is to start an entirely new JVM from your JVM (not easy), and then hard-kill that in order to try to 'abort' that blocking operation. That, itself, may not work (in which case, that's a pretty bad library, if it leaks a resource if its VM dies). That is quite a big gun to kill this particular mosquito, but it's the only one you have.

huangapple
  • 本文由 发表于 2020年10月6日 04:45:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/64215955.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定