Question

Note: I'm new to english, so please forgive me for any wrong in it.

I use thread-local for save a resource per-thread; and use it(thread-local) in a some tasks. I run my task by a java executor-service. I would close my resources when a thread going to terminate; then i need run a task in all created threads by executor-service, after me call "executor.shoutdown" method. how i can force executor to run a task per-thread, when it would terminate those?

import java.util.concurrent.*;

public class Main2 {

    public static void main(String[] args) {

        ExecutorService executor = new ForkJoinPool(3);
        SimpleValue val = new SimpleValue();
        for(int i=0; i<1000; i++){
            executor.execute(new Task(val));
        }

        executor.shutdown();
        while( true ) {
            try {
                if( executor.awaitTermination(1, TimeUnit.SECONDS) ) System.exit(0);
            } catch(InterruptedException intrExc) {
                // continue...
            }
        }
    }

    protected static interface ResourceProvider<T>
    extends AutoCloseable {
        public T get();
        public ResourceProvider<T> reset() throws Exception;
        public ResourceProvider<T> reset(boolean force) throws Exception;
        public void close();
    }

    protected static abstract class ThreadLocalResourceProvider<T>
    extends ThreadLocal<T>
    implements ResourceProvider<T> {}

    protected static class SimpleValue
    extends ThreadLocalResourceProvider<String> {
        public String initialValue() {
            return "Hello " + Thread.currentThread().getName();
        }
        public SimpleValue reset() throws Exception {
            return reset(false);
        }
        public SimpleValue reset(boolean force) throws Exception{
            set(this.initialValue());
            return this;
        }
        public void close() {
            remove();
        }
    }

    protected static class Task
    implements Runnable {

        protected SimpleValue val;
        public Task(SimpleValue val) {
            this.val = val;
        }

        @Override
        public void run() {
            try {
                System.out.print(val.reset().get());
            } catch( Exception exc ) {
                System.out.print( exc.getMessage() );
            }
        }
    }

}
Was it helpful?

Solution

Most executors can be constructed with a ThreadFactory. That's also true for ForkJoinPool. However, for simplification, I use a different ExecutorService.

ExecutorService executor = Executors.newFixedThreadPool(
    10, new FinalizerThreadFactory(Executors.defaultThreadFactory()));

The class FinalizerThreadFactory delegates the creation of threads to the passed thread factory. However, it creates threads that will execution some additional code before they exit. That's quite simple:

class FinalizerThreadFactory implements ThreadFactory {
    private final ThreadFactory delegate;
    public FinalizerThreadFactory(ThreadFactory delegate) {
        this.delegate = delegate;
    }
    public Thread newThread(final Runnable r) {
        return delegate.newThread(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    // finalizer code goes here.
                }
            }
        });
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top