Cancel file download from another thread at any time
I'm using HttpURLConnection to download a file. Can I cancel the download from another thread? If not, what method for file download开发者_开发知识库 should I use?
My suggestion would be to use HttpClient instead of HttpUrlConnection. It's a better library in many respects.
Then, you could use:
final SimpleHttpConnectionManager connectionManager =
new SimpleHttpConnectionManager();
final HttpClient client = new HttpClient(connectionManager);
// ... and when it's time to close the connection from another thread
connectionManager.shutdown();
If you need to close multiple connections across multiple threads, you can reuse one instance of HttpClient and close them all in one go in a similar fashion:
static MultiThreadedHttpConnectionManager connectionManager =
new MultiThreadedHttpConnectionManager();
// HttpClient instance that can be shared across threads and create multiple connections
static HttpClient client = new HttpClient(connectionManager);
// ... and when it's time to close connections
connectionManager.shutdown();
You can use the InterruptedException in conjunction with Tasks/Executors. Your spawned thread should be able to catch InterruptedException by wrapping the try/catch around the HttpURLConnection method that's doing the download. Java Concurrency In Practice, chapters 6 and 7 are relevant. Particularly 7.2 "Stopping a thread-based service".
I was able to get close()
on a InputStream to make a read()
return.
I realize this code is horrible. It effectively starts a server that listens on port 32323 for a HTTP connection. It will then read all the data available to it and write back bogus data until the client is able to obtain an InputStream. Once the client is able to obtain an input stream the server stops writing data simulating a broken download.
This is such a trivial example that it might not work in your real world scenario.
The client then closes the stream with InputStream.close()
which causes the InputStream.read()
to throw.
public class Main {
public static void main(String[] args) throws Exception {
final Object lock = new Object();
final boolean test[] = new boolean[1];
Thread thread = new Thread(new Runnable() {
public void run() {
try {
ServerSocket server = new ServerSocket(32323);
Socket socket = server.accept();
System.out.println("New client");
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
while (true) {
is.read();
///System.out.println(is.read());
if (!test[0]) {
os.write(0);
} else {
synchronized (lock) {
lock.notifyAll();
}
}
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
});
thread.start();
final InputStream[] asyncStream = new InputStream[1];
Thread thread2 = new Thread(new Runnable() {
public void run() {
try {
URL url = new URL("http://localhost:32323");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream is = connection.getInputStream();
System.out.println("got input stream");
asyncStream[0] = is;
test[0] = true;
while (true) {
System.out.print("read start");
is.read();
System.out.println(" done");
}
} catch (IOException ex) {
throw new RuntimeException("Read failed",ex);
}
}
});
thread2.start();
// wait enough time for data to run out
synchronized (lock) {
lock.wait();
}
System.out.println("Closing connection");
asyncStream[0].close();
System.out.println("Connection closed");
}
Output
New client
got input stream
read start done
read start done
read start done
read start done
read start done
read start done
read startClosing connection
done
read startRead failed
Connection closed
Did you try asynchronously closing connection's InputStream from another thread? Not sure if it's the right way, but it works with sockets so if Java uses similar design patter here it may work too. But even if it works, better look for a confirmation from some reliable source, though, as it may seem to work but fail sometimes as it often happens with multithreaded programming.
EDIT
Apparently, it doesn't work.
You can read the data chunk by chunk (normally you should do that way) and check a boolean flag which is set to true
(indicates stop) from another thread (consider using volatile
). Here the problem may be if reading chunk takes too long and it will wait for the chunk to be read before checking the flag. I'm not sure that closing the connection from another thread is a good idea (no info sources though). But if you do this, you can use a flag to distinguish real connection failures from stopping.
I assume you don't have access to the input stream or else you could just close it If not the next best thing to do is just set the thread priority to 0
This will minimize the number of time slices allocated to that thread.
InputStream.close()
may not work, but did you try HttpURLConnection.disconnect()
? If I'm not awfully wrong it should force disconnecting and thus InputStream.read()
should return -1. You should be sure to reconnect before continuing, though.
精彩评论