How to intercept Thread's lifecycle?

It is possible to create a log when creating a stream. We need to create a custom implementation ThreadFactory

from which all threads will be created, and from the method newThread

we can register it. But if we need to register when the stream is destroyed and disposed of, how can we do that?

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;

public enum MyThreadFactory implements ThreadFactory {
    INSTANCE;

    private final AtomicInteger poolNumber = new AtomicInteger(1);
    private final Logger logger = Logger.getLogger(getClass());
    private final ThreadGroup threadGroup;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    private RpiThreadFactory() {
        SecurityManager securityManager = System.getSecurityManager();
        threadGroup = (securityManager != null) ? securityManager.getThreadGroup() : Thread.currentThread().getThreadGroup();
        namePrefix = "RpiPool-" + poolNumber.getAndIncrement() + "-Thread-";

    }

    public Thread newThread(Runnable runnable) {
        Thread thread = new Thread(threadGroup, runnable, namePrefix + threadNumber.getAndIncrement(), 0);
        thread.setPriority(Thread.NORM_PRIORITY);
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

            public void uncaughtException(Thread thread, Throwable cause) {
                logger.error(cause.getMessage(), cause);
            }
        });

        logger.debug(thread.toString() + " created.");
        return thread;
    }
}

      

+3


source to share


2 answers


Since you are already implementing your own factory thread, one way would be to turn your runnable into another runnable that registers when the job starts and ends. Like this:

 public Thread newThread(Runnable runnable) {
     Runnable wrapper = new Runnable() {

        @Override
        public void run() {
            System.out.println("Starting thread ...");
            try {
                runnable.run();
                System.out.println("Thread done");
            } catch (Throwable t) {
                System.out.println("Thread exited abnormally");
                // Log exception
            }

        }

     };
     Thread thread = new Thread(threadGroup, wrapper, namePrefix + threadNumber.getAndIncrement(), 0);
    // ...
}

      



This does not register the actual life cycle of the thread, but is reliable compared to, for example, trusting the finalizer to register when the thread is destroyed.

Replace System.out.println

with log calls of your choice.

+5


source


You can create a proxy in Runnable

and create a stream using the proxy Runnable

, this way you have a handle to when the start method is started and ended



public enum RpiThreadFactory {
    INSTANCE;

    private final AtomicInteger poolNumber = new AtomicInteger(1);
    private final Logger logger = Logger.getLogger(this.name());
    private final ThreadGroup threadGroup;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    private RpiThreadFactory() {
        SecurityManager securityManager = System.getSecurityManager();
        threadGroup = (securityManager != null) ? securityManager.getThreadGroup() : Thread.currentThread().getThreadGroup();
        namePrefix = "RpiPool-" + poolNumber.getAndIncrement() + "-Thread-";
    }

    public Thread newThread(Runnable runnable) {
        Runnable proxyRunnable = (Runnable) Proxy.newProxyInstance(runnable.getClass().getClassLoader(), runnable.getClass().getInterfaces(),
            new RunnableProxy(runnable));
        Thread thread = new Thread(threadGroup, proxyRunnable, namePrefix + threadNumber.getAndIncrement(), 0);
        thread.setPriority(Thread.NORM_PRIORITY);
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

            public void uncaughtException(Thread thread, Throwable cause) {
            logger.fine(cause.getMessage());
            }
        });

        logger.fine(thread.toString() + " created.");
        return thread;
    }
}

class RunnableProxy implements InvocationHandler {
    private Runnable runnable;

    public RunnableProxy(Runnable runnable) {
        this.runnable = runnable;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Proxied Runnable Started!!");
        Object object = method.invoke(runnable, args);
        System.out.println("Proxied Runnable Done!!");
        return object;
    }
}

      

+1


source







All Articles