1

I have a thread which opens an url connection. I have a problem when I want to interrupt the thread. The Interrupted Exception is not thrown.

This code runs in my Thread

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"
    }
}

When I stop the thread theThread.interrupt() the request does not stop. When I use some dummy code (like while(true) Thread.sleep(500), the interrupt works correctly.

What am I doing wrong?

Peter
  • 1,011
  • 2
  • 16
  • 39
  • http://stackoverflow.com/questions/8284027/closing-an-httpurlconnection-before-the-response-is-complete might be of use http://stackoverflow.com/questions/15380993/how-to-stop-httpurlconnection-getinputstream – V H Jul 30 '15 at 19:43

1 Answers1

2

A trick to interrupt the thread is to cut off the input to the writer. This example illustrates the concept:

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'

In the example above, the RandomByteArrayInputStream simulates a large (endless actually) source of data. After sleeping, the main thread closes the RandomByteArrayInputStream, which causes the writer to stop writing, which causes the thread to finish up and stop.

Although the HttpURLConnection timeout plays a part, a similar concept can be used to interrupt writing to such a connection:

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()

Here, a subclass of Thread is used instead of an implementation of Runnable so that the interrupt method can close the input stream created from the XML data.

Note: I created ClosableByteArrayInputStream because calling the close method on a ByteArrayInputStream has no effect.

Emmanuel Rosa
  • 9,697
  • 2
  • 14
  • 20