views:

689

answers:

3

Hi all,
I want to manage a list of Futures objects returned by my TaskExecutor.
I've something like this

 List<Future<String>> list 

 void process(ProcessThis processThis) {     
    for ( ...) {
       Future<String> future = taskExecutor.submit(processThis);
       list.add(future)
    }
 }


 void removeFutures() {
    for(Future future : list) {
       assert future.cancel(true);
 }

ProcessThis is a task that implements Callable< String> and checks for Thread.interrupted() status

    public String call() {
        while (true) {
            if (Thread.interrupted()) {
                break;
            }
            doSomething();
        }
    }

Now the problem is that only a subset of the concurrent Threads is returning 'true' when Thread.interrupted() is called.
The assert in removeFutures() returns true for every future that is removed (I checked isDone() and isCompleted() as well.
The number of Threads that are interrupted is random. Over 15 running Threads sometimes 13 are interrupted, sometimes 2 ...
I really don't understand where's the issue. if I call future.cancel(true) and this returns true... and then I check Thread.interrupted (this is called only once), I expect this to return true as well.
Any idea of what am I missing?

I'm on build java 1.6.0_02-b05

+1  A: 

At least, you should restore the interruption flag to make taskExecutor aware of the thread interruption:

public String call() { 
    while (true) { 
        if (Thread.interrupted()) { 
            Thread.currentThread().interrupt();
            break; 
        } 
        doSomething(); 
    } 
} 
axtavt
thanks for your response. what's the point of doing this? If Thread.interrupted() returns true I break the while cycle and I basically kill the thread. The problem is that sometimes Thread.interrupted() returns 'false' even if the related future.cancel(true) returns true. The line you edited can't even be reached at that time.
marts
Then interruption flag is probably lost somewhere in `doSomething()` (for the same reason - something resets the flag and doesn't restore in). That is, sample in my answer is a basic principle that should be used to avoid lost interrupts
axtavt
If that's the case ('avoid lost interrupts') couldn't I just use something like Thread.currentThread().isInterrupted() instead of having to restore the interrupt state every time I use Thread.interrupted(). (BTW there's a bug with this: http://stackoverflow.com/questions/2012259/ ) I'm not dealing with the interrupt status in doSomething.
marts
+2  A: 

A potential problem that interrupts are often swallowed. So somewhere deep in doSomething() (or even in class loading), an interrupt may be caught by, say, wait() and then discarded by 'careless' code. Interrupts are evil, IMO.

It may be worth checking that all of you tasks are actually running at the time of the cancel.

Tom Hawtin - tackline
A: 

Be aware that Thread.interrupted() returns the current interrupted status and then clears it, so all future invocations will return false. What you want is probably Thread.currentThread().isInterrupted().

Also be aware that future.cancel(true) will usually only return false if the task had already been completed or canceled. If it returns true, that is no guarantee that the task will actually be canceled.

What is happening in doSomething()? Its possible that a RuntimeException is escaping somewhere due to the interrupt. Do you have an UncaughtExceptionHandler set? If not, you'll need to pass a ThreadFactory to the Executor that will set the exception handler and log any missed exceptions.

Kevin
I'm aware of this. I'm calling Thread.interrupted() only once after the while {. Anyway if it returns true I break; and kill the Thread immediately (and I don't touch/check the interrupt anywhere else). I'll have a look at the UncaughtExceptionHandler. thanks a lot for your response . (BTW be aware of this bug in Thread.currentThread().isInterrupted() http://bugs.sun.com/view_bug.do?bug_id=6772683)
marts
Currently, you're correctly using Thread.interrupted() in a safe manner. However, if you don't need the behavior provided by that method, you shouldn't use it as someone else (or you yourself) could refactor that method such that Thread.interrupted() is called in a way that invalidates the interrupt handling. Its much safer to use Thread.currentThread().isInterrupted() if you can.
Kevin
Hi Kevin. Your are right but due to java license issue I can't update the current JVM 1.6.0_02-b05. I'm running on a multi-processor machine and my JVM can be affected by the bug I linked in the previous comment (here is a related post in stackoverflow http://stackoverflow.com/questions/2012259/). About the unhandled exception, if a RuntimeException escape I can immagine that the thread die by its own, right? here my problem is the opposite.. they don't stop. (or at least a subset of them is stopped)
marts
1.) What java license issue? 2.) What is doSomething() doing? Does that properly respond to interruption?
Kevin