views:

312

answers:

4
+4  Q: 

Stopping a thread

In a java application,when the user hits download,establishing the remote connection and downloading the content from remote is done in a separate thread and a dialog is popped up in the screen to show the download progress. Now a cancel command has been added to the dialog inorder to provide the user with an option of cancelling the download. When the user hits cancel button, dialog can be disposed using dispose() method from the program but how can I stop/kill the thread which has already been initiated? Thread does the following task: 1.Establishes connection with remote 2.Downloads content from remote 3.stores the content locally (content is transferred via streaming) Please help me to resolve this issue

+4  A: 

You need to check for a stop flag somewhere in your download routine.

public DownloadThread implements Runnable {
    private boolean stop;
    public void stop() { stop = true; }
    public void run() {
        while (!stop) {
            // download a block, save it somewhere
        }
    }
}

Of course this lacks the necessary synchronization but that’s about how you stop a thread without using the deprecated Thread.stop().

Bombe
The OP says that he's using streaming I/O, so they may be using a while loop to pull down and store the data. They can perform the stop check inside that loop. If they're grabbing it all in one chuck, though, then they're stuffed.
skaffman
As "jgubby" points out, the stop variable above should be volatile.
Fredrik
@Fredrik I do not agree with that claim. See my comment on jgubby's answer
Yuval A
+3  A: 

Firstly, the stop() operation on java.util.Thread is deprecated, and its use is strongly discouraged, since it can leave things in an unstable state. It's much preferred that you send a message to the Thread's Runnable asking it to stop itself safely.

The problem you have is that your thread is doing blocking I/O operations, and so it won't receive your message until the I/O is complete.

The best you can hope for, unless someone else comes up with a better option, is to interrupt() the Thread, and hope that the I/O classes notice and stop the download.

Edit: The javadoc for Thread.interrupt() does say that I/IO can be interrupted if you use java.nio, but it's very unlikely that you are. "Normal" java.io traffic is blocking, and cannot be interrupted.

Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?

skaffman
IIRC, interruptible IO has only been enabled by default on Solaris. Interrupt is generally evil.
Tom Hawtin - tackline
@Tom - can you expand on 'interrupt is generally evil', pls ?
Brian Agnew
e.vil (adj): characterized or accompanied by misfortune or suffering; unfortunate; disastrous
skaffman
You don't know what you are interrupting (may be class loading or some implementation detail), interrupts are generally not handled correctly and the meaning of an interrupt is often not clear in the local context.
Tom Hawtin - tackline
+5  A: 

Stopping a thread is probably the wrong way to look at. The actual resource consumed by a single thread on a desktop machine is irrelevant. Think of it as aborting the download.

If the read is blocking, then that isn't really much of a problem. You can wait until there is some data before not reading again. A more abrupt approach would be to call close on the stream (from another thread).

Tom Hawtin - tackline
+1 for calling close on the stream (as a last resort)
Harry Lime
+1  A: 

I suggest you do what Bombe suggested (with a volatile variable) and just leave the thread to die in the background, returning control back to the user. It might spend a little while fetching the last block, but if the user can carry on doing something else it doesn't matter too much. If your block sizes were relatively small the wasted bandwidth wont be too much, and the IO stuff will timeout eventually and return if the connection has gone bad.


public class Downloader {
    protected final AtomicBoolean run = new AtomicBoolean(false);
    protected final byte[] file;
    protected volatile double progress = 0.0;    

    public download(URL url) {
        run.set(true);
        new Thread() {
            @Override
            public run() {
                final ByteBuffer buffer = new ByteBuffer();
                while(run) {
                    /* download chunk, e.g add to buffer, or whatever */
                    buffer.put(chunk);
                    progress = buffer.size().size() / fileTotalSize; //e.g
                }
                syncrhonized(Downloader.this) {
                    file = buffer.array();
                }
            }
        }.start();
    }

    public void abort() {
        run.set(false);
    }

    public double getProgress() {
        return progress;
    }

    public synchronized byte[] getFile() {
        return file;
    }
}
jgubby
I do not agree with making the variable volatile. It will hurt performance in each loop. While if you keep the variable non-volatile, the only penalty you will get is a slight delay (which you can't even measure) in the stopping of the thread.
Yuval A
I disagree with that comment. Compared to the latency of network operations, setting of a volatile variable is *tiny* - whereas a program that relies on the eventual propagation of data between threads is actually incorrect. Don't optimise away synchronisation for the sake of speed!
jgubby
Setting a volatile variable is indeed no issue. But accessing a volatile variable means it is not in thread cache - thus hurting performance. I agree optimizations shouldn't be made prematurely, but if this loop is of importance, this should be considered.
Yuval A
Downloading content from remote not done in while iteration.Code is executed in mobile app and when user selects download content, the content is downloaded via GPRS.JavaME does not have nio.Herewith I have provided the pseudo code.new Thread(new Runnable(){try{//open http connection to remote server//display dialog with progress indicator and cancel command//obtain input stream from remote connection//read stream byte by byte (update progress indicator)//store content via output stream}catch(IOException ioe){}}).start(); when user clicks cancel command, how can i abort this thread?
I suggest you edit your original post and add the code...
jgubby