Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why restore interrupt flag of a task that ran in a thread pool's thread

This snippet is from JCIP (Brian Goetz) listing 6.15

f.get() throws InterruptedException and ExecutionException. Now, these exceptions are specific to the future correct? Meaning the specific task represented by the future was interrupted or had an internal exception.

Questions -

  1. Why do I need to restore the interrupt using "Thread.currentThread().interrupt()"? , because isnt the interrupt flag for the thread my task ran in? This is a little confusing.

  2. Why throw launderThrowable exception? If one of the downloadImage had an issue, shouldnt we just process the other downloaded images intead of throwing from here and thus just "not" processing the remaining futures?

    package net.jcip.examples;
    
    import java.util.*;
    import java.util.concurrent.*;
    import static net.jcip.examples.LaunderThrowable.launderThrowable;
    
    /**
     * Renderer
     * <p/>
     * Using CompletionService to render page elements as they become available
     *
     * @author Brian Goetz and Tim Peierls
     */
    public abstract class Renderer {
        private final ExecutorService executor;
    
        Renderer(ExecutorService executor) {
            this.executor = executor;
        }
    
        void renderPage(CharSequence source) {
            final List<ImageInfo> info = scanForImageInfo(source);
            CompletionService<ImageData> completionService =
                    new ExecutorCompletionService<ImageData>(executor);
            for (final ImageInfo imageInfo : info)
                completionService.submit(new Callable<ImageData>() {
                    public ImageData call() {
                        return imageInfo.downloadImage();
                    }
                });
    
            renderText(source);
    
            try {
                for (int t = 0, n = info.size(); t < n; t++) {
                    Future<ImageData> f = completionService.take();
                    ImageData imageData = f.get();
                    renderImage(imageData);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                throw launderThrowable(e.getCause());
            }
        }
    
        interface ImageData {
        }
    
        interface ImageInfo {
            ImageData downloadImage();
        }
    
        abstract void renderText(CharSequence s);
    
        abstract List<ImageInfo> scanForImageInfo(CharSequence s);
    
        abstract void renderImage(ImageData i);
    
    }
    
like image 217
FatherFigure Avatar asked Jul 12 '11 00:07

FatherFigure


2 Answers

When you catch InterruptedException interrupted flag gets reset and your thread is technically not interrupted anymore. However, you don't know if the code that called your code (or other code in the same thread), requires any additional interrupt handling. By calling interrupt() you raise the flag again and effectively saying to the rest of the application "This thread is still interrupted - act on it if necessary".

Consider example. You method is called from the loop that must terminate if thread is interrupted. You caught the exception and if you don't raise the flag, the loop will not terminate as required.

like image 113
Alex Gitelman Avatar answered Oct 04 '22 16:10

Alex Gitelman


By catching InterruptedException, you are stopping the interruption from reaching the Thread in which you are running. But you want it to reach it, in case there is any special processing the Thread needs to do in case of interruption - you can't tell, so you'd better play it safe and allow it to percolate up. You may do some processing yourself (to clean up, exit what you are doing, etc), but you must pass it on. The best way to do this is to call Thread.currentThread().interrupt().

like image 43
Bohemian Avatar answered Oct 04 '22 16:10

Bohemian