如何在Java线程中断时停止URL连接

如何在Java线程中断时停止URL连接,java,multithreading,url,Java,Multithreading,Url,我有一个访问URL的多线程程序。线程通过executor服务运行,当用户选择通过GUI退出时,程序将通过调用executor.shutdownNow()尝试中断线程。但是,程序需要很长时间才能关闭,因为许多线程在url.openStream()调用中被阻塞,而且由于这不会引发InterruptedException,因此到目前为止,我被迫只检查Thread.currentThread().isInterrupted()调用前后的情况 我想知道是否有更好的方法在线程中断时中断URL连接?否则,让程

我有一个访问URL的多线程程序。线程通过executor服务运行,当用户选择通过GUI退出时,程序将通过调用
executor.shutdownNow()
尝试中断线程。但是,程序需要很长时间才能关闭,因为许多线程在
url.openStream()
调用中被阻塞,而且由于这不会引发
InterruptedException
,因此到目前为止,我被迫只检查
Thread.currentThread().isInterrupted()调用前后的情况

我想知道是否有更好的方法在线程中断时中断URL连接?否则,让程序尽快关闭的最佳方法是什么


请注意,我不希望在连接上设置超时,因为我希望在程序仍在运行时访问所有URL。

如果您查看Javadocs for,它会提示您:如果您在URLConnection上调用getInputStream或getOutputStream,然后关闭其中一个流,它将关闭连接。如果您一直在等待getInput/OutputStream调用,那么我认为什么都做不到。但是如果您有这个流,那么关闭它(它将抛出一个IOException并释放在流上等待的所有线程),连接就完成了


仅供参考:我发现,这种在您希望输入流超时或只是想停止处理时关闭输入流的方法非常有效,比使用interrupt()更有效。

简单的答案是使用
System.exit(0)
,这将迫使所有线程死亡

使用Apache HttpClient

最好使用ApacheHttpClient而不是
URLConnection
。这是一种比
URLConnection
更高级的客户端方式,它更易于使用,而且可中断。缺点是,默认情况下,它并没有包含在所有Java环境中,因此它可能会导致软件附带的额外依赖性。如果没关系,那就去做吧

如果您必须坚持使用
URLConnection

现在网络上的URL通常使用HTTP或HTTPS,因此您的
URLConnection
可能实际上分别属于
HttpURLConnection
HttpsURLConnection
类型。如果是这样的话,你是幸运的。后者比
URLConnection
(见下文)有一个关键优势。首先,您需要强制转换到
HttpURLConnection
。在URL中使用HTTP或HTTPS时,可以安全地执行此操作

HttpURLConnection conn = (HttpURLConnection) url.openConnection();
HttpURLConnection
还有一个附加方法,
disconnect()
,您现在可以使用它。调用此方法会导致
getInputStream()
,或在此类流上的
read()
调用中阻塞的任何线程抛出
SocketException:socketclosed

conn.disconnect();
警告
javadoc对
disconnect()
给出了相反的观点:

如果出现以下情况,调用
disconnect()
方法可能会关闭底层套接字: 否则,永久连接在当时处于空闲状态


然而,我已经在Ubuntu和Android下的JDK1.8中对它进行了测试,它在两种环境中都能以完全相同的方式很好地工作,所以文档中的这句话实际上不是真的,也许它不应该是真的,因为这是中断
URLConnection
的唯一方法。甚至当客户端和服务器都指示它们可以保持连接的活动状态时,甚至当没有“其他空闲连接”时,它也可以工作。

我将使用JAX-RS http client。它支持异步请求。请原谅我使用Kotlin,但您使用Java的方式是相同的

//compile 'org.glassfish.jersey.core:jersey-client:2.0.1'
import javax.ws.rs.client.ClientBuilder

val th = Thread {
  val urlString = "http://long.running.page"
  val cli = ClientBuilder.newClient()
  val fut = cli.target(urlString).request().async().get()
  println(fut.get())
}
th.start()
println("wait")
Thread.sleep(3000)
println("interrupt")
th.interrupt()
th.join()

在对@DanielS answer发表评论后,我还发现了使用
HttpAsyncClients
的示例。因此,它似乎支持中断,但不支持
HttpClient
类。

我认为大部分时间都花在等待
openConnection()
,然后是
getInputStream()
。。。事实上,似乎在后者上花费了更多的时间。还有什么我能做的吗?我不喜欢使用这个,因为还有其他线程可能被阻塞的调用,比如写入数据库等等,我需要确保所有的资源都被清理掉。好吧,那为什么不加入()所有这些线程(非URLConnection线程),并调用exit()呢一旦只剩下URLConnection了?如果不是那么简单,那么我承认exit()是一个糟糕的选项。请注意,
conn.connect()
不能被
disconnect()
中断,所以这里您唯一的选择就是设置连接超时。而且,您无法绕过
connect()
,因为如果您不在代码中直接调用它,它会被
getInputStream()
调用。似乎Apache HttpClient也不可中断<代码>执行
方法不会抛出
中断异常