When submitting tasks to java executor service, some thread will be allocated to perform that task. The servicing thread may be assigned from the internal thread pool, or created on-demand. Each executor service has an associated ThreadFactory, and a default ThreadFactory if the application does not specify one. For non-trivial apps, it's always a good idea to set a custom ThreadFactory.

1, To set a more descriptive thread name. With the default ThreadFactory, it gives thread names in the form of pool-m-thread-n, such as pool-1-thread-1, pool-2-thread-1, pool-3-thread-1, etc. When these threads showing up in debugger, profiler, or monitoring tool, it's hard to know their purpose and how they were started.

When analyzing a thread dump, thread name is the only clue to trace to the source where the thread pool or executor service is created.  The stack trace contains all JDK classes with java.lang.Thread.run at the very bottom.  It doesn't tell anything about your application.

2, To set thread daemon status. The default ThreadFactory produces non-daemon threads.

3, To set thread contextClassLoader to appropriate value. Threads created by the default ThreadFactory will inherit the contextClassLoader from the parent thread, which may not be what you want. In general, a pooled thread itself should not be associated with any specific class loader. Instead, the submitted task has the best knowledge about its class loading requirement, so the task Runnable or Callable should manage the thread contextClassLoader for the duration of its run method.

If the new thread does not need to access classes loaded in the parent thead, set its contextClassLoader to null. If a task needs visibility to a class loader, set its contextClassLoader at the beginning of its run method, and restore its contextClassLoader right before exiting run method.

The default ThreadFactory in JDK 6 java.util.concurrent is a package-private static nested class in java.util.concurrent.Executors:
static class DefaultThreadFactory implements ThreadFactory {
        static final AtomicInteger poolNumber = new AtomicInteger(1);
        final ThreadGroup group;
        final AtomicInteger threadNumber = new AtomicInteger(1);
        final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null)? s.getThreadGroup() :
                                 Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
Note that poolNumber is declared as static final and threadNumber as final. Each instance of ThreadFactory is tied to a unique pool, and a static poolNumber tracks the sequence of all instances of DefaultThreadFactory. An instance of ThreadFactory (and the associated pool) contains multiple threads, and the instance field threadNumber tallies all threads therein.

Both poolNumber and threadNumber fields are of type java.util.concurrent.AtomicInteger to take advantage of its atomic compound operations. Their initial value is 1 and getAndIncrement() is invoked to produce sequence like 1, 2, 3. Alternatively we could set its initial value to 0 and invoke incrementAndGet() to produce the same sequence.

Why poolNumber and threadNumber need to guard against concurrent access and modification? poolNumber is static and thus a shared data among all instances of DefaultThreadFactory. Multiple instances of DefaultThreadFactory may be incrementing it simutaneously, so it needs to be thread-safe.

As for threadNumber, the creation of threads, either initially at execution service startup time, or under heavy load, may be serialized by the execution service. But an instance of ThreadFactory can be passed around and associated with multiple execution service. Therefore, the internal state of ThreadFactory needs to be thread-safe and immutable.
0

Add a comment

Labels
Archive
Popular Posts
Popular Posts
  • Two JVM options are often used to tune JVM heap size: -Xmx for maximum heap size, and -Xms for initial heap size. Here are some common mi...
  • Simple enum . The ; after the last element is optional, when this is the end of enum definition. public enum Color { WHITE, BLACK, RED, ...
  • How to set project classpath in Eclipse and NetBeans are similar: just right-click the project name, choose Properties to bring up the Prope...
  • Let's say I need to spawn multiple threads to do the work, and continue to the next step only after all of them complete. I will need t...
  • This is a sample web.xml based on Servlet 2.5 (part of Java EE 5) that declares common elements. All top-level elements are optional, and c...
  • The default string value for java enum is its face value, or the element name. However, you can customize the string value by overriding toS...
  • Prior to JDK 6, we can check if a string is empty in 2 ways: if(s != null && s.length() == 0) if(("").equals(s)) Checking ...
  • When writing javadocs, IntelliJ automatically adds a closing tag for html elements. For instance, after typing <lt>, it automaticaly a...
  • StringBuilder was introduced in JDK 1.5. What's the difference between StringBuilder and StringBuffer? According to javadoc , StringBu...
  • With array, we can easily declare and initialize it at the same time: String[] favorites = new String[] {"EJB", "JPA", ...
Loading