简体   繁体   中英

Thread of a Runnable is not being destroyed after execution

My code base is quite big, so I will try to put it here as concise as possible.

I am under the assumptions that if a Runnable finishes execution inside a Thread , that then both the Thread and the Runnable will be destroyed, as the code inside the Runnable is linear code, well maybe some function calls, but definitely no loops.

The issue is that the Thread does remain to be running, while I think it should not.

Creation of the RunnableProcessor :

Controller.getInstance().getNamedThreadFactory().addThreadName("EST: " + runnableProcessor.toString());
Controller.getInstance().getExecutorService().execute(runnableProcessor);

The RunnableProcessor class:

public class RunnableProcessor<T> implements Runnable {
    private final Processor<T> processor;
    private final T object;

    public RunnableProcessor(final Processor<T> processor, final T object) {
        this.processor = processor;
        this.object = object;
    }

    @Override
    public void run() {
        processor.process(object);
    }

    @Override
    public String toString() {
        return "RunnableProcessor(\"" + processor + "\", \"" + object.toString() + "\")";
    }
}

An example of such a Processor , namely InputProcessor :

public class InputProcessor implements Processor<File> {
    private static final String PDF = "pdf";

    @Override
    public void process(File file) {
        if (new CustomPath(file).getExtension().equalsIgnoreCase(PDF)) {
            processPdf(file);
        }
        else {
            processImage(file);
        }
    }

    private void processPdf(final File file) {
        System.out.println("Processing " + file.toString());
        FileEditor.convert(file);
        Utils.move(file.toPath(), new File(Controller.DONE_URL + File.separator + file.getName()).toPath());
        System.out.println("Processed");
    }

    private void processImage(final File file) {
        //Skew detection
        System.out.println("Rotating " + file.toString());
        SkewDetector skewDetector = new SkewDetector(file);
        File rotatedFile = skewDetector.detect();
        Utils.move(rotatedFile.toPath(), new File(Controller.ROTATED_INPUT_URL + File.separator + rotatedFile.getName()).toPath());
        System.out.println("Rotated");
    }

    @Override
    public String toString() {
        return "InputProcessor";
    }
}

Nothing in the code blocks the execution, that is in this case the specific strings Processed or Rotated are all being printed to System.out , and after that the specific Thread still does not die. This is for example one of the threads still being alive, even though execution of the Runnable finished, the name is: EST: RunnableProcessor("InputProcessor", "D:\\OCR\\renamed_input\\682-converted.tiff") .

The behaviour of the thread, over two minutes measured, seems interesting though: It follows this sequence: Shortly running, shortly being monitored, long running, quick monitor, short running, very long wait, relative short running, very long wait, relative short running, waiting (until eternity?).

Can anyone help figure out what exactly is going on?

You seem to be using an executor service. While it could be implemented to create new threads for each task it can, and apparently in your case is, implemented using a thread pool that keeps threads waiting for new tasks to run. According to the documentation this is done for better performance.

You should not depend on the inner workings of the executor service anyway. If you need to be notified when your task is done I'd recommend to monitor the task or the/a wrapper.

If you want to create a new wrapper and seem to be polling (the thread status) anyway it can be as simple as:

void run() {
    innerRunner.run();  // the wrapped runner
    doneFlag = true;    // a boolean indicating the status
}

You might need to call

Controller.getInstance().getExecutorService().shutdown();
Controller.getInstance().getExecutorService().awaitTermination();

To shutdown your thread pool.

You use the thread pool that create fixed number of threads. Thread pool reuses created threads for tasks execution( Runnable, Callable ). You can't explicit destroy threads, because threads are manageable thread pool.

As you said @Andrey Chaschev you should call it:

Controller.getInstance().getExecutorService().shutdown();
Controller.getInstance().getExecutorService().awaitTermination();

for threads termination.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM