Soru Java'da ThreadFactory kullanımı


Birisi HOW ve WHEN üzerinde bir ThreadFactory kullanmak için kısaca açıklayabilir mi? ThreadFactory kullanmadan ve kullanmadan bir örnek, farklılıkları anlamak için gerçekten yardımcı olabilir.

Teşekkürler!


44
2017-07-05 13:13


Menşei


Güneş açıklamasının oldukça yararlı olduğunu düşünüyorum: java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/... Ayrıca, fabrika modeli itsef de açıklanmalıdır: en.wikipedia.org/wiki/Factory_method_pattern - InsertNickHere


Cevaplar:


Fabrika modeli, nesnelerin oluşturulmasında yer alan süreçleri kapsüllemek için yazılım geliştirmede kullanılan bir tasarım modelidir.

Farklı görevler için bazı çalışan iş parçacığımız olduğunu varsayalım ve bunları özel isimlerle isteyin (hata ayıklama amaçlı olsun). Böylece bir ThreadFactory uygulayabiliriz:

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

Böyle bir gereksiniminiz varsa, bir fabrika veya yapımcı deseni olmadan uygulamak oldukça zor olacaktır.


ThreadFactory Java API'nın bir parçasıdır, çünkü diğer sınıflar tarafından da kullanılır. Yukarıdaki örnekte, bazı durumlarda 'Threads' oluşturmak için bir fabrikayı neden kullanmalıyız, ama elbette, kesinlikle uygulamaya gerek yok. java.util.concurrent.ThreadFactory Bu görevi yerine getirmek için.


40
2017-07-05 13:37



ThreadFactory, arayanın ThreadGroup, ContextClassLoader ve AccessControlContext (genellikle bir iş parçacığı olan ve bir kuyruğa düşüren "thread") olan newThread (Runnable) öğesini kullandığı için bu oldukça kötü bir örnektir. En azından ThreadGroup c-torda referans olarak tutulacak ve thread ile oluşturulmalıdır. - bestsss
@bestsss - ThreadFactory bir arayüzdür, kullanır hiçbir şey değil. Basit örnek, sınıfın kendi dokümantasyonu tarafından sağlanan örneğe yakındır ve odak fabrika düzenine konulmuştur. Sağlamak için çekinmeyin iyi örnek kendi cevabınız ile. - Andreas_D
yorum rahatsız edici değildi ve ThreadFactory belgesinde yazılanların çok iyi farkındayım. Executors.defaultThreadFactory () ve Executors.privilegedThreadFactory () iyi bir başlangıç ​​noktasıdır (özellikle ikinci) (onlar herhangi bir aklı başında adlandırma yok) olsa da, Executors.privilegedThreadFactory () dokümanı da oldukça iyi. - bestsss
Sayacın atomik olması ya da en azından uçucu olması gerekmez, aksi takdirde birden fazla iş parçacığı eşzamanlı olarak oluşturulmuşsa aynı sayaca sahip olabilir. - Marcus
@ @@@@@@@@@@@@@@@@@@@@ sayaç bir AtomicInteger olarak bildirilmelidir. - CaptainHastings


İşte olası bir kullanım. Eğer çalıştırılabilir görevlerinizi çok iş parçacıklı bir şekilde yürüten ve bir süre içinde iş parçacığınız yakalanmamış bir istisnadan ölen bir yürütücü hizmetiniz varsa. Tüm bu istisnaları günlüğe kaydetmediğinizi varsayalım. ThreadFactory bu problemi çözer:

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

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

LoggingThreadFactory Bunun gibi uygulanabilir:

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

55
2017-07-05 13:49



Yıllarca sonra bu yorum için beni affedin, ama bu örnek yanıltıcıdır. ExecutorService.submit () aracılığıyla gönderilen Runnable görevleri tarafından atılan özel durum, UncaughtExceptionHandler tarafından yakalanmayacak, yalnızca ExecutorService.execute () işlenecektir. - Abdhul Lathif Riswan


Bazı iç çalışmalar

Konu kolayca görülemeyen bazı iç eserler dışında oldukça iyi kaplıdır. Yeni oluşturulmuş iş parçacığı w / the constructor oluştururken geçerli iş parçacıklarını devralır:

  • ThreadGroup (ürünle birlikte verilmezse veya System.getSecurityManager().getThreadGroup() keyfi döndürür ThreadGroup) - Kendi başına iplik grubu, bazı durumlarda önemli olabilir ve yanlış iplik sonlandırma / kesintiye neden olabilir. ThreadGroup varsayılan istisna işleyici olarak duracaktır.
  • ContextClassLoader - Çevrenin CCL'yi değiştirmesi gerektiği için büyük bir sorun olmaması gereken yönetilen bir ortamda, ancak bunu uygularsanız - bunu aklınızda bulundurun. Arayanın CCL'sini sızdırmak oldukça kötüdür, yani thread grubu da (eğer threadGroup bazı alt sınıfsa ve doğrudan değilse) java.lang.ThreadGroup - geçersiz kılmaya ihtiyacım var ThreadGroup.uncaughtException)
  • AccessControlContext - burada, sadece içsel kullanım için olduğu ve az da olsa varlığından şüphe ettiğinden, (özel bir iş parçasından başlamak hariç) neredeyse yapılacak hiçbir şey yoktur.
  • Yığın boyutu (genellikle belirtilmemiş ama arayan kişiye dayalı olarak çok dar yığın büyüklüğüne sahip bir iş parçacığı alabilir)
  • öncelik - çoğu insan bunu bilir ve (daha fazla veya daha az)
  • daemon durumu - genellikle bu çok önemli ve kolay fark edilebilir değildir (uygulama kaybolursa)
  • Son olarak: iş parçacığı devralır InheritableThreadLocal - bazı imalara yol açabilir (ya da olmayabilir). İpliği özel bir iş parçacığı haline getirmenin yanı sıra, hiçbir şey yapılamaz.

Uygulamaya bağlı olarak, yukarıdaki noktaların hiçbir şekilde bir etkisi olmayabilir, ancak bazı durumlarda, bunların bazıları belirleyici davranışları tespit etmek ve sergilemek zor olan Sınıf / Kaynak sızıntılarına yol açabilir.


Bu ekstra uzun bir yazı yapardı ama ...

aşağıda bazı (umarım) yeniden kullanılabilir kodu ThreadFactory Uygulama, düzgün sağlamak için yönetilen ortamlarda kullanılabilir ThreadGroup (önceliği veya kesintileri sınırlayabilir), ContextClassLoader, stacksize ve benzeri ayarlanır (ve / veya yapılandırılabilir) ve sızdırmaz. Herhangi bir ilgi varsa, devralınanlarla nasıl başa çıkılacağını gösterebilirim ThreadLocals veya devralınan acc (aslında çağrıyı sızdırabilir 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;
    }
}

Ayrıca bazı çok basit kullanım:

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

16
2018-01-19 00:14



Bu, Google Guava'nın ThreadFactoryBuilder’ine benziyor. Her ne kadar ClassLoader'ı sizin gibi ele aldıklarına inanmıyorum. Görmek guava-libraries.googlecode.com/svn/tags/release05/javadoc/com/... - Darwyn
@Darwyn, Guava hakkında hiçbir şey bilmiyorum (bir şekilde kullanmıyorum ve kodunu incelemedim), yukarıdaki kod tamamen kişisel deneyimlerden geliyor. Aslında sınıf yükleyici kullanımı herhangi bir ara yazılım için zararlı, hatta yeterince stres atamam. - bestsss


IMHO bir tek en önemli işlevi ThreadFactory iş parçacığı yararlı bir şey isimlendiriyor. Bir stacktrace adlı iş parçacığına sahip olmak pool-1-thread-2 veya daha kötüsü Thread-12 Problemleri teşhis ederken tam bir ağrıdır.

Tabi ki bir ThreadGroup, daemon durumu ve önceliği de yararlıdır.


4
2017-07-06 02:13





"InsertNickHere" tarafından belirtildiği gibi, anlamanız gerekir Fabrika desen.

ThreadFactory kullanımı için iyi bir örnek ThreadPoolExecutor: Gerekirse, Yürütücü Gerekli Konular oluşturacak ve havuza dikkat edecektir. Oluşturma işlemine adım atmak ve oluşturulan Thread'lere özel isimler vermek ya da bir ThreadGroup'a atamak istiyorsanız, bu amaçla bir ThreadFactory oluşturabilir ve Executor'a verebilirsiniz.

Birazcık IoC-style.


2
2017-07-05 13:51





Özel iplik fabrikasını kullanmak her zaman iyi bir uygulamadır. Varsayılan fabrikalar çok fazla kullanılmamaktadır. Aşağıdaki nedenlerden dolayı özel bir fabrika kullanmalısınız:

  1. Özel iş parçacığına sahip olmak
  2. İş parçacığı arasında seçim yapmak için
  3. İplik Önceliğini Seçmek İçin
  4. Yakalanmamış istisnaları işlemek için

Bu gönderiyi kontrol et: http://wilddiary.com/understanding-java-threadfactory-creating-custom-thread-factories/


2
2017-09-12 10:55





Java'da ThreadFactory kullanımı

İstek üzerine yeni thread oluşturan bir nesne. İplik fabrikalarını kullanmak, çağrıların kablolu bağlantılarını kaldırır new Threaduygulamaların özel iş parçacığı alt sınıflarını, önceliklerini vb. kullanmasını sağlar.

Bu arayüzün en basit uygulaması sadece:

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

ThreadPoolExecutor.java'nın 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;
        }
    }

Kaynak


2
2018-01-16 06:00





ThreadFactory, tek bir yöntemle bir arabirimdir public abstract java.lang.Thread newThread(java.lang.Runnable arg0);

Kullanımı sizin ihtiyacınıza göre değişir. Daemon iş parçacıklarını her zaman oluşturmak için belirli bir işlevsellik istediğinizi varsayalım. Bunu ThreadFactory ile kolayca başarabilirsiniz.

Aşağıdaki kod sadece temelini anlatmak içindir. Belirli bir işlevsellik yapmıyor.

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

1
2018-01-25 06:09





Şuna baksana VerboseThreads (uygular ThreadFactory) jcabi-log. Bu uygulama yapar ThreadBu günlükleri dışarı atıldıklarında istisnalar. Konularınızın ne zaman ve neden öldüğünü görmeniz gerektiğinde çok kullanışlı bir sınıf.


0
2018-01-02 15:49