【问题标题】:How to intercept Thread lifecycle?如何拦截线程生命周期?
【发布时间】:2015-06-05 08:29:07
【问题描述】:

创建线程时可以记录。我们需要有一个自定义的ThreadFactory 实现,所有线程都将从该实现中创建,并且我们可以从newThread 方法记录它。但是如果我们需要在线程被销毁和删除时记录日志,我们该怎么做呢?

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;
    }
}

【问题讨论】:

  • 您是否尝试使用自己的线程池?是否存在您需要管理自己的线程池的有效案例?
  • “当线程被删除时”是什么意思?从哪里/什么删除?
  • 你可以返回而不是返回 WorkerThread extends Thread 并且在完成时有一个对 MyThreadFactory 的回调

标签: java multithreading lifecycle


【解决方案1】:

由于您已经在实现自己的线程工厂,因此一种方法是将您的可运行对象包装到另一个可运行对象中,该可运行对象会在作业开始和完成时记录日志。像这样:

 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);
    // ...
}

这不会记录实际的线程生命周期,但与信任终结器在线程被销毁时进行记录相比,它是可靠的。

用您选择的记录调用替换 System.out.println。

【讨论】:

  • 你也应该重新投掷。并使用真正的日志库而不是 System.out.println 进行日志记录。
  • @lllogiq 真正的日志库是的,但我喜欢在我的答案中避免其他依赖项。我不同意重新抛出,如果异常实际上是从 run 方法抛出的,它将最终出现在线程的异常处理程序中。我更喜欢明确地处理它。但它应该被记录下来。
  • 关于日志记录没问题,但您至少应该正确处理 InterruptedException,请参阅daniel.mitterdorfer.name/articles/2015/…
  • @lllogiq 我在这段代码中没有阻塞操作。我根本看不出InterruptedException 的处理是如何相关的。请详细说明。
  • @lllogiq 此外,Runnable.run() 不能抛出 InterruptedException。这是一个检查异常。
【解决方案2】:

您可以在Runnable 上创建一个代理并使用代理的Runnable 创建一个线程,这样您就可以知道运行方法何时开始和结束

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;
    }
}

【讨论】:

    猜你喜欢
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-12
    • 1970-01-01
    • 1970-01-01
    • 2011-04-11
    • 2016-09-08
    相关资源
    最近更新 更多