The fundamental problem is to terminate a thread externally -safely.
An Event Dispatching Thread (EDT) spawns a new worker thread (workerThread). This workerThread has to complete a task. The task is completed in several iterations of a loop. Each iteration has two parts-read data(IO), compute data(Digest). workerThread can be signaled for cancellation by EDT at any time via a boolean flag(FLAG_CANCEL) inside workerThread's code. Here's the problem-the only time the flag is checked is after IO and/or after digest. This provides instant cancellation upto the sub-iteration level.
What I want is cancellation during IO or during Digest. Repetitively checking Thread.interrupted is the same as FLAG_CANCEL checking.That doesn't work. Since IO and Digest don't throw any InterruptedExceptions(nor can they be modified to do so), workerThread.interrupt() doesn't work(nothing in the loop gets interrupted).
- How to terminate IO or Digest in-situ?
- Can I use Thread.stop() safely(safely as in re-initializing unsafe-monitor-exposed-objects)?
Here's the EDT invocation
private final Runnable runnable= new Runnable() {
@Override
public void run() {
try {
//hasher is a global instance in EDT of Hasher class
hasher.hash(file);
} catch (NoSuchAlgorithmException ex) {
//do something
} catch (IOException ex) {
//do something
}
catch (InterruptedException ex) {
//do something
}
}
};
Thread workerThread=new Thread(runnable);
workerThread.setDaemon(true);
workerThread.start();
Here's the method for class Hasher
synchronized public String hash(File file) throws NoSuchAlgorithmException, FileNotFoundException, IOException
{
FLAG_CANCEL_HASHING = false;//global
byte[] buffer =new buffer[calculateBufferSize()];
MessageDigest md = MessageDigest.getInstance(algorithm);
FileInputStream fis = new FileInputStream(file);
int bytesRead;
float totalBytesRead = 0;
//start hashing
while ((bytesRead = fis.read(buffer)) != -1)//IO
{
//check before Digest
if (FLAG_CANCEL_HASHING)
{
fireCancellationEvent();
return null;
}
md.update(buffer, 0, bytesRead);//Digest
//check before IO
iif (FLAG_CANCEL_HASHING)
{
fireCancellationEvent();
return null;
}
totalBytesRead += bytesRead;
fireProgressEvent(totalBytesRead );
}
fis.close();
return toHexString(md.digest());
}
Can I call workerThread.stop() and then use hasher safely afterwards in my next invocation of runnable?
Towards a solution-is it absolutely enough (towards ensuring nothing messes up in the next call to hasher from EDT)
to do workerThread.stop in EDT &&
reinitialize hasher, FLAG_CANCEL_HASHING &&
ignore all fired events after cancellation,
explicitly close fis(first having made it global)
(basically make a new hasher instance in EDT)
Remember all is need is for termination during resource intensive IO or Digest to not affect the working of any successive calls to hasher. For e.g. after killing the thread by stop, will calling rutime.getRuntime.gc clean up the exposed objects and prevent any ill behaviour in the next call to hasher?