使用线程池的时候我们一定都会自定义线程池,而线程池有一个参数是 ThreadFactory, 它的工作就是生产线程。(设置线程池的目的则是为了在jstack的时候看到这个线程在做什么)

    1. public interface ThreadFactory {
    2. /**
    3. * Constructs a new {@code Thread}. Implementations may also initialize
    4. * priority, name, daemon status, {@code ThreadGroup}, etc.
    5. *
    6. * @param r a runnable to be executed by new thread instance
    7. * @return constructed thread, or {@code null} if the request to
    8. * create a thread is rejected
    9. */
    10. Thread newThread(Runnable r);
    11. }

    线程池在创建代码的时候,也离不开 Thread 的实例化和初始化的过程,而线程初始化又会涉及到 ThreadLocal 的传递。

    1. private Thread(ThreadGroup g, Runnable target, String name,
    2. long stackSize, AccessControlContext acc,
    3. boolean inheritThreadLocals) {
    4. if (inheritThreadLocals && parent.inheritableThreadLocals != null)
    5. this.inheritableThreadLocals =
    6. ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    7. }

    从这里可以看到,ThreadLocal的配置不会传递到子线程,而inheritableThreadLocals会传递到子线程,这里的子线程的含义不仅包括了new 出来的thread,同时也包括线程池产生的thread。

    这里就会涉及到一个问题,当父线程中的 inheritableThreadLocals有数据的时候,子线程是可以获取到的,这里如果辨别不当,就会有哎,都还没设置呢,怎么子线程就有数据了呢的误区。 其实是 inheritableThreadLocals 在这里发生了重要作用。

    单独把这一块拿出来说可能大家都不陌生,但是如果把线程池的含义扩大化,扩大的Tomcat,扩大到jetty里边,然后再来看这个过程就不是那么容易了。

    例如项目初始化的时候,Tomcat使用main线程设置了一个数据,然后tomcat线程明明没有设置,为什么里边就有数据呢。 它的数据哪里来的呢。这里就是线程池的扩大。