如何在 Grails 的线程中中断 HttpUrlConnection?

How to interrupt HttpUrlConnection in a thread in Grails?

我有一个线程可以打开 url 连接。当我想中断线程时遇到问题。不会抛出中断异常。

此代码在我的线程中运行

public void run() {
    try {
        final HttpURLConnection connection =new URL(url).openConnection()        
        connection.setReadTimeout(600000)
        connection.setRequestMethod("POST")
        connection.outputStream.withWriter { Writer writer ->
            writer << requestxml
    } catch (InterruptedException ie) {
        println "interrupted"
    } catch (Exception e) {
         println "other error"
    }
}

当我停止线程 theThread.interrupt() 时,请求不会停止。 当我使用一些伪代码(如 while(true) Thread.sleep(500) 时,中断工作正常。

我做错了什么?

中断线程的一个技巧是切断对作者的输入。这个例子说明了这个概念:

class RandomByteArrayInputStream extends InputStream {
    def rand = new Random()
    def isClosed = false

    int read() {
        if(isClosed) {
            -1
        } else {
            rand.nextInt((90 - 65) + 1) + 65;
        }
    }

    void close() {
        isClosed = true
    }
}

def input = new RandomByteArrayInputStream()
def output = new ByteArrayOutputStream()

println 'Starting background thread.'
def t = Thread.start {
    output.withWriter {w ->
        w << input
    }
    println 'Oh darn, ran out of input.'
}

println 'Sleeping...'
Thread.currentThread().sleep(5000)
println 'Awake! Closing input stream.'
input.close()
println 'Done'

在上面的例子中,RandomByteArrayInputStream 模拟了一个大的(实际上是无穷无尽的)数据源。休眠后,主线程关闭RandomByteArrayInputStream,导致writer停止写入,导致线程写完停止。

虽然 HttpURLConnection 超时起到一定作用,但可以使用类似的概念来中断写入此类连接:

class ClosableByteArrayInputStream extends ByteArrayInputStream {
    def isClosed = false

    public ClosableByteArrayInputStream(String string) {
        super(string as byte[])
    }

    int read() {
        isClosed ? -1 : super.read()       
    }

    void close() {
        isClosed = true
    }
}

class MyThread extends Thread { 
    private InputStream inputStream

    def url
    def requestxml

    public void run() { 
        final HttpURLConnection connection = url.openConnection()         
        connection.setReadTimeout(600000) 
        connection.setRequestMethod("POST")
        connection.doOutput = true
        inputStream = new ClosableByteArrayInputStream(requestxml)

        connection.outputStream.withWriter { Writer writer -> 
            writer << inputStream
        }     
    } 

    public void interrupt() { 
        inputStream?.close()
        super.interrupt()        
    } 
} 

def t = new MyThread()
t.url = 'URL GOES HERE'.toURL()
t.requestxml = 'DATA GOES HERE'
t.start()

// Do whatever...

t.interrupt()

此处,使用 Thread 的子类而不是 Runnable 的实现,以便 interrupt 方法可以关闭从 XML 数据创建的输入流。

注意:我创建了 ClosableByteArrayInputStream,因为在 ByteArrayInputStream 上调用 close 方法没有任何效果。