सवाल जावा में थ्रेड फैक्टरी उपयोग


क्या कोई थ्रेडफैक्टरी का उपयोग करने के लिए कैसे और कब संक्षेप में समझा सकता है? थ्रेडफैक्टरी का उपयोग किए बिना और बिना किसी उदाहरण में मतभेदों को समझने में वास्तव में सहायक हो सकता है।

धन्यवाद!


44
2017-07-05 13:13


मूल


मुझे लगता है कि सूर्य की व्याख्या काफी उपयोगी है: java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/... इसके अलावा, कारखाना पैटर्न itsef समझाया जाना चाहिए: en.wikipedia.org/wiki/Factory_method_pattern - InsertNickHere


जवाब:


कारखाना पैटर्न वस्तुओं के निर्माण में शामिल प्रक्रियाओं को समाहित करने के लिए सॉफ्टवेयर विकास में उपयोग किए जाने वाले एक रचनात्मक डिजाइन पैटर्न है।

आइए मान लें कि हमारे पास विभिन्न कार्यों के लिए कुछ कार्यकर्ता धागे हैं और उन्हें विशेष नामों के साथ चाहते हैं (डीबगिंग उद्देश्यों के लिए कहें)। तो हम एक थ्रेड फैक्टरी लागू कर सकते हैं:

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

यदि आपके पास ऐसी आवश्यकता थी, तो कारखाने या निर्माता पैटर्न के बिना इसे लागू करना बहुत कठिन होगा।


ThreadFactory जावा एपीआई का हिस्सा है क्योंकि इसका इस्तेमाल अन्य वर्गों द्वारा भी किया जाता है। तो उपरोक्त उदाहरण से पता चलता है कि हमें कुछ अवसरों में 'थ्रेड बनाने के लिए कारखाने का उपयोग क्यों करना चाहिए, लेकिन, निश्चित रूप से, लागू करने की बिल्कुल आवश्यकता नहीं है java.util.concurrent.ThreadFactory इस काम को पूरा करने के लिए।


40
2017-07-05 13:37



यह एक बहुत बुरा उदाहरण है क्योंकि थ्रेडफैक्टरी कॉलर के थ्रेड ग्रुप, कॉन्टेक्स्ट क्लासलोडर और एक्सेसकंट्रोलकॉन्टेक्स्ट (न्यू थ्रेड (रननेबल) का उपयोग करता है जो आम तौर पर धागे का उत्पादन होता है और कतार में ड्रॉप करता है)। कम से कम थ्रेड ग्रुप को सी-टोर में संदर्भ के रूप में रखा जाएगा और धागे के साथ बनाया जाना चाहिए। - bestsss
@bestsss - ThreadFactoryएक इंटरफेस है, यह उपयोग करता है कुछ भी तो नहीं। सरल उदाहरण कक्षा के अपने दस्तावेज द्वारा प्रदान किया गया उदाहरण बंद है और फ़ैक्टरी पैटर्न पर ध्यान केंद्रित किया गया था। एक प्रदान करने के लिए स्वतंत्र महसूस करें अच्छा उदाहरण अपने उत्तर में - Andreas_D
टिप्पणी आक्रामक नहीं थी और मुझे थ्रेड फैक्ट्री के दस्तावेज़ में जो लिखा गया है, उसके बारे में अच्छी तरह से पता है। निष्पादक .defaultTreadFactory () और निष्पादक ..privilegedTreadFactory () अच्छे शुरुआती बिंदु हैं [बाद में esp] (हालांकि उनमें किसी भी नामकरण की कमी है), निष्पादक के दस्तावेज़। PrivilegedTreadFactory () काफी सभ्य है। - bestsss
काउंटर को परमाणु या कम से कम अस्थिर होने की आवश्यकता नहीं होगी, अन्यथा एकाधिक धागे समान काउंटर हो सकते हैं यदि वे समवर्ती रूप से बनाए जाते हैं। - Marcus
@ मार्कस अस्थिरता परमाणुता की गारंटी नहीं देता है यदि दो धागे एक साथ नए थ्रेड को कॉल करना चाहते थे। काउंटर को परमाणु इंटेगर के रूप में घोषित किया जाना चाहिए। - CaptainHastings


यहां एक संभावित उपयोग है। यदि आपके पास एक निष्पादक सेवा है जो आपके चलने योग्य कार्यों को मल्टीथ्रेडेड फ़ैशन में निष्पादित करती है और एक बार थोड़ी देर में आपका धागा बिना किसी अपवाद से मर जाता है। आइए मान लें कि आप इन सभी अपवादों को लॉग इन नहीं करना चाहते हैं। ThreadFactory इस समस्या को हल करता है:

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

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

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

55
2017-07-05 13:49



कई वर्षों के बाद इस टिप्पणी के लिए मुझे माफ़ कर दो, लेकिन यह उदाहरण भ्रामक है। ExecorService.submit () के माध्यम से सबमिट किए गए रननेबल कार्यों द्वारा निकाला गया अपवाद, UncaughtExceptionHandler द्वारा पकड़ा नहीं जाएगा, केवल execorService.execute () को संभाला जाएगा - Abdhul Lathif Riswan


कुछ आंतरिक कार्य

विषय को कुछ आंतरिक कार्यों को छोड़कर काफी अच्छी तरह से कवर किया गया है जो आसानी से दिखाई नहीं दे रहे हैं। एक थ्रेड डब्ल्यू / कन्स्ट्रक्टर बनाने के दौरान नव निर्मित धागे को मौजूदा थ्रेड प्राप्त होते हैं:

  • ThreadGroup (जब तक आपूर्ति या नहीं System.getSecurityManager().getThreadGroup() मनमाने ढंग से लौटता है ThreadGroup) - कुछ मामलों में धागा समूह अपने दाहिनी ओर महत्वपूर्ण हो सकता है और परिणामस्वरूप अनुचित धागा समाप्ति / बाधा उत्पन्न हो सकती है। ThreadGroup डिफ़ॉल्ट अपवाद हैंडलर के रूप में खड़ा होगा।
  • ContextClassLoader - प्रबंधित वातावरण में जो एक महान मुद्दा नहीं होना चाहिए क्योंकि पर्यावरण सीसीएल स्विच करेगा, लेकिन यदि आप इसे लागू करना चाहते हैं - इसे ध्यान में रखें। कॉलर के सीसीएल को लेना काफी खराब है, इसलिए धागा समूह (esp। अगर थ्रेड ग्रुप कुछ सबक्लास है और सीधे नहीं है java.lang.ThreadGroup - ओवरराइड करने की जरूरत है ThreadGroup.uncaughtException)
  • AccessControlContext - यहां, लगभग कुछ भी करने के लिए नहीं है (एक समर्पित धागे में शुरू करने के अलावा) क्योंकि क्षेत्र केवल आंतरिक उपयोग के लिए है, और कुछ लोगों के अस्तित्व पर संदेह भी है।
  • स्टैक आकार (आमतौर पर इसे निर्दिष्ट नहीं किया जाता है लेकिन कॉलर के आधार पर थ्रेड डब्ल्यू / बहुत संकीर्ण स्टैक आकार प्राप्त करने के लिए यह एक चीज हो सकती है)
  • प्राथमिकता - ज्यादातर लोग इसे जानते हैं और इसे सेट करते हैं (अधिक या कम)
  • डेमॉन स्थिति - आमतौर पर यह बहुत महत्वपूर्ण और आसानी से उल्लेखनीय नहीं है (यदि एप्लिकेशन अभी गायब हो जाता है)
  • अंत में: थ्रेड कॉलर की विरासत में आता है InheritableThreadLocal - जो कुछ प्रभावों का कारण बन सकता है (या नहीं)। धागे को एक समर्पित धागे में फैलाने के अलावा, कुछ भी नहीं किया जा सकता है।

आवेदन के आधार पर उपर्युक्त बिंदुओं पर कोई प्रभाव नहीं पड़ सकता है, लेकिन कुछ मामलों में, उनमें से कुछ कक्षा / संसाधन लीक का कारण बन सकते हैं जो निर्धारक व्यवहार का पता लगाने और प्रदर्शित करने में कठोर हैं।


इससे एक अतिरिक्त लंबी पोस्ट होगी लेकिन ...

नीचे कुछ (उम्मीद है) पुन: प्रयोज्य कोड है ThreadFactory कार्यान्वयन, इसे उचित वातावरण सुनिश्चित करने के लिए प्रबंधित वातावरण में उपयोग किया जा सकता है ThreadGroup (जो प्राथमिकता को सीमित कर सकता है या धागे को बाधित कर सकता है) ContextClassLoader, stacksize और इतने पर सेट हैं (और / या कॉन्फ़िगर किया जा सकता है) और लीक नहीं। यदि कोई दिलचस्पी है तो मैं दिखा सकता हूं कि w / विरासत में कैसे निपटें ThreadLocals या विरासत एसीसी (जो अनिवार्य रूप से कॉलिंग रिसाव कर सकते हैं 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;
    }
}

इसके अलावा कुछ बहुत ही सरल उपयोग:

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

16
2018-01-19 00:14



यह Google Guava के ThreadFactoryBuilder के समान लगता है। हालांकि मुझे विश्वास नहीं है कि वे क्लासलोडर को आपके जैसा करते हैं। देख guava-libraries.googlecode.com/svn/tags/release05/javadoc/com/... - Darwyn
@ डार्विन, मुझे अमरूद के बारे में कुछ भी पता नहीं है (जिस तरह से मैं इसका उपयोग नहीं करता हूं और मैंने इसका कोड नहीं पढ़ा है), ऊपर दिया गया कोड पूरी तरह से व्यक्तिगत अनुभव से आता है। असल में क्लासलोडर हैंडलिंग किसी भी मिडलवेयर के लिए हानिकारक है, मैं भी पर्याप्त तनाव नहीं दे सकता। - bestsss


आईएमएचओ एक का सबसे महत्वपूर्ण कार्य है ThreadFactory थ्रेड कुछ उपयोगी नामकरण कर रहा है। नाम के एक स्टैक्र्रेस में धागे होने के बाद pool-1-thread-2 या खराब Thread-12 समस्याओं का निदान करते समय एक पूर्ण दर्द है।

बेशक, एक है ThreadGroup, डेमन स्थिति और प्राथमिकता भी सभी उपयोगी हैं।


4
2017-07-06 02:13





जैसा कि "InsertNickHere" द्वारा उल्लिखित है, आपको समझना होगा फैक्टरी पैटर्न

थ्रेड फैक्ट्री के उपयोग के लिए एक अच्छा उदाहरण है ThreadPoolExecutor: यदि आवश्यक हो तो निष्पादक थ्रेड बनायेगा और पूलिंग का ख्याल रखेगा। यदि आप निर्माण प्रक्रिया में कदम उठाना चाहते हैं और बनाए गए थ्रेड के लिए विशेष नाम देना चाहते हैं, या उन्हें थ्रेड ग्रुप को असाइन करना चाहते हैं, तो आप उस उद्देश्य के लिए थ्रेडफ़ैक्टरी बना सकते हैं और इसे निष्पादक को दे सकते हैं।

यह थोड़ा सा है आईओसी-अंदाज।


2
2017-07-05 13:51





कस्टम थ्रेड फैक्ट्री का उपयोग करना हमेशा एक अच्छा अभ्यास है। डिफ़ॉल्ट कारखानों का उपयोग बहुत अधिक नहीं है। निम्नलिखित कारणों से आपको कस्टम फैक्ट्री का उपयोग करना चाहिए:

  1. कस्टम थ्रेड नाम रखने के लिए
  2. थ्रेड प्रकारों के बीच चयन करने के लिए
  3. थ्रेड प्राथमिकता चुनने के लिए
  4. बेजोड़ अपवादों को संभालने के लिए

इस पोस्ट को जांचें: http://wilddiary.com/understanding-java-threadfactory-creating-custom-thread-factories/


2
2017-09-12 10:55





जावा में थ्रेड फैक्टरी उपयोग

एक वस्तु जो मांग पर नए धागे बनाती है। थ्रेड कारखानों का उपयोग करने से कॉल की हार्डवायरिंग को हटा दिया जाता है new Thread, अनुप्रयोगों को विशेष थ्रेड उपclass, प्राथमिकताओं, आदि का उपयोग करने में सक्षम बनाता है।

इस इंटरफेस का सबसे सरल कार्यान्वयन सिर्फ है:

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

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

स्रोत


2
2018-01-16 06:00





थ्रेड फैक्टरी एक विधि के साथ एक इंटरफ़ेस है public abstract java.lang.Thread newThread(java.lang.Runnable arg0);

इसका उपयोग आपकी आवश्यकता पर निर्भर करता है। मान लीजिए कि आप हमेशा डेमॉन थ्रेड बनाने के लिए एक विशेष कार्यक्षमता चाहते हैं। आप आसानी से थ्रेड फैक्ट्री के साथ इसे प्राप्त कर सकते हैं।

नीचे दिया गया कोड केवल मौलिक कहने के लिए है। यह कोई विशिष्ट कार्यक्षमता नहीं कर रहा है।

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