Java 中的 ThreadFactory 用法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3179733/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 17:09:44  来源:igfitidea点击:

ThreadFactory usage in Java

javamultithreadingconcurrency

提问by jagamot

Can someone briefly explain on HOW and WHEN to use a ThreadFactory? An example with and without using ThreadFactory might be really helpful to understand the differences.

有人可以简要解释一下如何以及何时使用 ThreadFactory 吗?使用和不使用 ThreadFactory 的示例可能真的有助于理解差异。

Thanks!

谢谢!

采纳答案by Andreas Dolk

The factory pattern is a creational design pattern used in software development to encapsulate the processes involved in the creation of objects.

工厂模式是一种创建性设计模式,用于软件开发中,用于封装对象创建所涉及的过程。

Let's assume we have some worker threads for different tasks and want them with special names (say for debugging purposes). So we could implement a ThreadFactory:

假设我们有一些用于不同任务的工作线程,并希望它们具有特殊的名称(例如出于调试目的)。所以我们可以实现一个ThreadFactory:

public class WorkerThreadFactory implements ThreadFactory {
   private int counter = 0;
   private String prefix = "";

   public WorkerThreadFactory(String prefix) {
     this.prefix = prefix;
   }

   public Thread newThread(Runnable r) {
     return new Thread(r, prefix + "-" + counter++);
   }
}

If you had such a requirement, it would be pretty difficult to implement it without a factory or builder pattern.

如果您有这样的需求,那么在没有工厂或构建器模式的情况下实现它会非常困难。



ThreadFactoryis part of the Java API because it is used by other classes too. So the example above shows why we should use 'a factory to create Threads' in some occasions but, of course, there is absolutely no need to implement java.util.concurrent.ThreadFactoryto accomplish this task.

ThreadFactory是 Java API 的一部分,因为它也被其他类使用。所以上面的例子说明了为什么在某些情况下我们应该使用“工厂来创建线程”,但是,当然,绝对不需要实现java.util.concurrent.ThreadFactory来完成这个任务。

回答by Boris Pavlovi?

Here's one possible usage:

这是一种可能的用法:

Assume you have an ExecutorServicewhich executes your Runnabletasks in a multithreaded fashion, and once in a while a thread dies from an uncaught exception. Let's also assume that you want to log all of these exceptions. ThreadFactorysolves this problem by allowing you to define a uniform logger for uncaught exceptions in the Runnablethat the thread was executing:

假设您有一个以多线程方式ExecutorService执行您的Runnable任务,并且偶尔有一个线程因未捕获的异常而死亡。我们还假设您想记录所有这些异常。ThreadFactory通过允许您为Runnable线程正在执行的未捕获异常定义统一的记录器来解决这个问题:

ExecutorService executor = Executors.newSingleThreadExecutor(new LoggingThreadFactory());

executor.submit(new Runnable() {
   @Override
   public void run() {
      someObject.someMethodThatThrowsRuntimeException();
   }
});

LoggingThreadFactorycan be implemented like this one:

LoggingThreadFactory可以这样实现:

public class LoggingThreadFactory implements ThreadFactory
{

    @Override
    public Thread newThread(Runnable r)
    {
        Thread t = new Thread(r);

        t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
        {
            @Override
            public void uncaughtException(Thread t, Throwable e)
            {
                LoggerFactory.getLogger(t.getName()).error(e.getMessage(), e);
            }
        });

        return t;
    }
}


The ThreadFactoryinterface is a flexible interface that allows the programmer to handle uncaught exceptions as shown above, but also allows much more control over the creation details of a Thread(like defining a pattern for the thread name) making it quite useful for debugging purposes and production environments alike.

ThreadFactory接口是一个灵活的接口,允许程序员处理未捕获的异常,如上所示,但也允许更多地控制 a 的创建细节Thread(例如为线程名称定义模式),使其对于调试目的和生产环境非常有用一样。

回答by Hardcoded

As mentioned by "InsertNickHere", you'll have to understand the Factory Pattern.

正如“InsertNickHere”所提到的,您必须了解工厂模式

A good example for a use of a ThreadFactory is the ThreadPoolExecutor: The Executor will create Threads if necessary and take care of the pooling. If you want to step in at the creation process and give special names to the created Threads, or assign them to a ThreadGroup, you can create a ThreadFactory for that purpose and give it to the Executor.

使用 ThreadFactory 的一个很好的例子是ThreadPoolExecutor:如果需要,Executor 将创建线程并处理池化。如果您想介入创建过程并为创建的线程赋予特殊的名称,或者将它们分配给一个线程组,您可以为此目的创建一个 ThreadFactory 并将其提供给 Executor。

It's a little bit IoC-style.

它有点IoC风格。

回答by Jed Wesley-Smith

IMHO the single most important function of a ThreadFactoryis naming threads something useful. Having threads in a stacktrace named pool-1-thread-2or worse Thread-12is a complete pain when diagnosing problems.

恕我直言, a 最重要的功能ThreadFactory是为线程命名一些有用的东西。在诊断问题时,在 stacktrace 中使用线程命名pool-1-thread-2或更糟Thread-12是一个完全的痛苦。

Of course, having a ThreadGroup, daemon status and priority are all useful too.

当然,拥有ThreadGroup守护进程状态和优先级也很有用。

回答by bestsss

Some inner workings

一些内部运作

The topic is covered quite well except for some inner works that are not easily visible. While creating a thread w/ the constructor the newly created thread inherits current threads:

除了一些不容易看到的内部作品外,该主题涵盖得很好。在使用构造函数创建线程时,新创建的线程继承当前线程:

  • ThreadGroup(unless supplied or System.getSecurityManager().getThreadGroup()returns arbitrary ThreadGroup) - The thread group on its right own can be important in some cases and can result in improper thread termination/interruption. The ThreadGroupwill stand as default exception handler.
  • ContextClassLoader- in managed environment that should not be a great issue since the environment shall switch the CCL, but if you are to implement that - keep it mind. Leaking the caller's CCL is quite bad, so is the thread group (esp. if the threadGroup is some subclass and not direct java.lang.ThreadGroup- need to override ThreadGroup.uncaughtException)
  • AccessControlContext- here, there is virtually nothing to be done (except starting in a dedicated thread) since the field is for internal usage only, and few even suspect the existence of.
  • stack size (usually it's unspecified but it can a -fun- thing to get a thread w/ very narrow stack size, based on the caller)
  • priority - most people do know about and tend to set it (more or less)
  • daemon status - usually that's not very important and easily noticable (if the application just disappears)
  • Lastly: the thread inherits caller's InheritableThreadLocal- which may (or may not) lead to some implications. Again nothing can be done about, besides spawning the thread into a dedicated thread.
  • ThreadGroup(除非提供或System.getSecurityManager().getThreadGroup()返回任意ThreadGroup) - 在某些情况下,线程组本身可能很重要,并可能导致线程终止/中断不当。该ThreadGroup会站在作为默认的异常处理。
  • ContextClassLoader- 在托管环境中,这应该不是一个大问题,因为环境会切换 CCL,但是如果您要实现它 - 请记住。泄漏调用者的 CCL 非常糟糕,线程组也是如此(特别是如果 threadGroup 是某个子类而不是直接的java.lang.ThreadGroup- 需要覆盖ThreadGroup.uncaughtException
  • AccessControlContext- 在这里,几乎没有什么可做的(除了在专用线程中启动),因为该字段仅供内部使用,很少有人怀疑其存在。
  • 堆栈大小(通常它是未指定的,但是根据调用者获得具有非常窄堆栈大小的线程可能是一件有趣的事情)
  • 优先级 - 大多数人确实知道并倾向于设置它(或多或少)
  • 守护进程状态 - 通常这不是很重要并且很容易被注意到(如果应用程序刚刚消失)
  • 最后:线程继承调用者的InheritableThreadLocal——这可能(也可能不会)导致一些影响。同样,除了将线程生成为专用线程之外,什么也做不了。

Depending on the application the points above may have no effect at all but in some cases, some of them can lead to Class/Resources leaks that are hard to detect and exhibit not deterministic behavior.

根据应用程序,上述几点可能根本没有影响,但在某些情况下,其中一些可能导致难以检测并表现出不确定行为的类/资源泄漏。



That would make an extra long post but so...

那将是一篇超长的帖子,但...

below is some (hopefully) reusable code for ThreadFactoryimplementation, it can be used in managed environments to ensure proper ThreadGroup(which can limit priority or interrupt threads), ContextClassLoader, stacksize and so on are set (and/or can be configured) and not leaked. If there is any interest I can show how to deal w/ inherited ThreadLocalsor the inherited acc (which essentially can leak the calling classloader)

下面是一些(希望)用于ThreadFactory实现的可重用代码,它可以在托管环境中使用以确保正确ThreadGroup(可以限制优先级或中断线程)、ContextClassLoader、堆栈大小等设置(和/或可以配置)并且不会泄漏。如果有任何兴趣,我可以展示如何处理继承ThreadLocals或继承的 acc(这基本上可以泄漏调用classloader

package bestsss.util;

import java.lang.Thread.UncaughtExceptionHandler;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;

public class ThreadFactoryX implements ThreadFactory{
    //thread properties
    long stackSize;
    String pattern;
    ClassLoader ccl;
    ThreadGroup group;
    int priority;
    UncaughtExceptionHandler exceptionHandler;
    boolean daemon;

    private boolean configured;

    private boolean wrapRunnable;//if acc is present wrap or keep it
    protected final AccessControlContext acc;

    //thread creation counter
    protected final AtomicLong counter = new AtomicLong();

    public ThreadFactoryX(){        
        final Thread t = Thread.currentThread();
        ClassLoader loader;
    AccessControlContext acc = null;
    try{
        loader =  t.getContextClassLoader();
        if (System.getSecurityManager()!=null){
            acc = AccessController.getContext();//keep current permissions             
            acc.checkPermission(new RuntimePermission("setContextClassLoader"));
        }
    }catch(SecurityException _skip){
        //no permission
        loader =null;
        acc = null;
    }

    this.ccl = loader;
    this.acc = acc;
    this.priority = t.getPriority();    
    this.daemon = true;//Executors have it false by default

    this.wrapRunnable = true;//by default wrap if acc is present (+SecurityManager)

    //default pattern - caller className
    StackTraceElement[] stack =  new Exception().getStackTrace();    
    pattern(stack.length>1?getOuterClassName(stack[1].getClassName()):"ThreadFactoryX", true);     
    }

    public ThreadFactory finishConfig(){
        configured = true;
        counter.addAndGet(0);//write fence "w/o" volatile
        return this;
    }

    public long getCreatedThreadsCount(){
        return counter.get();
    }

    protected void assertConfigurable(){
        if (configured)
            throw new IllegalStateException("already configured");
    }

    private static String getOuterClassName(String className){
        int idx = className.lastIndexOf('.')+1;
        className = className.substring(idx);//remove package
        idx = className.indexOf('$');
        if (idx<=0){
            return className;//handle classes starting w/ $
        }       
        return className.substring(0,idx);//assume inner class

    }

    @Override
    public Thread newThread(Runnable r) {
        configured = true;
        final Thread t = new Thread(group, wrapRunnable(r), composeName(r), stackSize);
        t.setPriority(priority);
        t.setDaemon(daemon);
        t.setUncaughtExceptionHandler(exceptionHandler);//securityException only if in the main group, shall be safe here
        //funny moment Thread.getUncaughtExceptionHandler() has a race.. badz (can throw NPE)

        applyCCL(t);
        return t;
    }

    private void applyCCL(final Thread t) {
        if (ccl!=null){//use factory creator ACC for setContextClassLoader
            AccessController.doPrivileged(new PrivilegedAction<Object>(){
                @Override
                public Object run() {
                    t.setContextClassLoader(ccl);
                    return null;
                }                               
            }, acc);        
        }
    }
    private Runnable wrapRunnable(final Runnable r){
        if (acc==null || !wrapRunnable){
            return r;
        }
        Runnable result = new Runnable(){
            public void run(){
                AccessController.doPrivileged(new PrivilegedAction<Object>(){
                    @Override
                    public Object run() {
                        r.run();
                        return null;
                    }                               
                }, acc);
            }
        };
        return result;      
    }


    protected String composeName(Runnable r) {
        return String.format(pattern, counter.incrementAndGet(), System.currentTimeMillis());
    }   


    //standard setters allowing chaining, feel free to add normal setXXX    
    public ThreadFactoryX pattern(String patten, boolean appendFormat){
        assertConfigurable();
        if (appendFormat){
            patten+=": %d @ %tF %<tT";//counter + creation time
        }
        this.pattern = patten;
        return this;
    }


    public ThreadFactoryX daemon(boolean daemon){
        assertConfigurable();
        this.daemon = daemon;
        return this;
    }

    public ThreadFactoryX priority(int priority){
        assertConfigurable();
        if (priority<Thread.MIN_PRIORITY || priority>Thread.MAX_PRIORITY){//check before actual creation
            throw new IllegalArgumentException("priority: "+priority);
        }
        this.priority = priority;
        return this;
    }

    public ThreadFactoryX stackSize(long stackSize){
        assertConfigurable();
        this.stackSize = stackSize;
        return this;
    }


    public ThreadFactoryX threadGroup(ThreadGroup group){
        assertConfigurable();
        this.group= group;
        return this;        
    }

    public ThreadFactoryX exceptionHandler(UncaughtExceptionHandler exceptionHandler){
        assertConfigurable();
        this.exceptionHandler= exceptionHandler;
        return this;                
    }

    public ThreadFactoryX wrapRunnable(boolean wrapRunnable){
        assertConfigurable();
        this.wrapRunnable= wrapRunnable;
        return this;                        
    }

    public ThreadFactoryX ccl(ClassLoader ccl){
        assertConfigurable();
        this.ccl = ccl;
        return this;
    }
}

Also some very simple usage:

还有一些非常简单的用法:

ThreadFactory factory = new TreadFactoryX().priority(3).stackSize(0).wrapRunnable(false).pattern("Socket workers", true).
daemon(false).finishConfig();

回答by yegor256

Take a look at VerboseThreads(implements ThreadFactory) from jcabi-log. This implementation makes Threads that log exceptions when they are being thrown out of them. Very useful class when you need to see when and why your threads die.

jcabi-log看一下VerboseThreads(implements ThreadFactory) 。此实现使s 在抛出异常时记录异常。当您需要查看线程何时以及为何死亡时,该类非常有用。Thread

回答by Drona

It is always a good practice to use custom thread factory. The default factories are not much of use. You should use a custom factory for the following reasons:

使用自定义线程工厂始终是一个好习惯。默认工厂用处不大。出于以下原因,您应该使用自定义工厂:

  1. To have custom thread names
  2. To choose between thread types
  3. To choose Thread Priority
  4. To handle uncaught exceptions
  1. 拥有自定义线程名称
  2. 在螺纹类型之间进行选择
  3. 选择线程优先级
  4. 处理未捕获的异常

Check this post: http://wilddiary.com/understanding-java-threadfactory-creating-custom-thread-factories/

检查这篇文章:http: //wilddiary.com/understanding-java-threadfactory-creating-custom-thread-factories/

回答by Aalekh

ThreadFactory is an interface with a single method public abstract java.lang.Thread newThread(java.lang.Runnable arg0);

ThreadFactory 是一个具有单一方法的接口 public abstract java.lang.Thread newThread(java.lang.Runnable arg0);

Its usage depends on your requirement. Suppose you want a particular functionality to always create Daemon threads. You can easily achieve this with ThreadFactory.

它的用法取决于您的要求。假设您希望特定功能始终创建守护进程线程。您可以使用 ThreadFactory 轻松实现这一点。

The below code is just for telling the fundamental. It is not doing any specific functionality.

下面的代码只是为了告诉基本。它没有做任何特定的功能。

package TestClasses;
import java.util.concurrent.ThreadFactory;
public class ThreadFactoryEx implements ThreadFactory{
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
}

package TestClasses;
import java.util.concurrent.ThreadPoolExecutor;
public class RunnableEx implements Runnable{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 5; i++) {
            System.out.println("in a loop" + i + "times");
        }
    }
}


package TestClasses;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Thread1 {
    public static void main(String[] args) {
        ExecutorService exe = Executors.newCachedThreadPool(new ThreadFactoryEx());
        for (int i = 0; i < 4; i++) {
            exe.execute(new RunnableEx());
        }
    }
}

回答by Premraj

ThreadFactory usage in Java

Java 中的 ThreadFactory 用法

An object that creates new threads on demand. Using thread factories removes hardwiring of calls to new Thread, enabling applications to use special thread subclasses, priorities, etc.

按需创建新线程的对象。使用线程工厂消除了对 调用的硬连线new Thread,使应用程序能够使用特殊的线程子类、优先级等。

The simplest implementation of this interface is just:

这个接口最简单的实现就是:

class SimpleThreadFactory implements ThreadFactory {
   public Thread newThread(Runnable r) {
     return new Thread(r);
   }
 }

DefaultThreadFactory of ThreadPoolExecutor.java

ThreadPoolExecutor.java 的 DefaultThreadFactory

static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private 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;
        }
    }

Source

来源

回答by ravthiru

ThreadFactorywill be useful

ThreadFactory会很有用

  • for setting more descriptive thread name
  • to set thread daemon status
  • for setting thread priority
  • 用于设置更具描述性的线程名称
  • 设置线程守护进程状态
  • 用于设置线程优先级

You could use ThreadFactoryBuilderfrom google Guava lib to create ThreadFactorylike this

你可以使用ThreadFactoryBuilder谷歌番石榴库来创建ThreadFactory这样的

ThreadFactory threadFactory = new ThreadFactoryBuilder()
        .setNameFormat("MyThreadPool-Worker-%d")
        .setDaemon(true)
        .build();