सवाल क्या कोई निष्पादक सेवा है जो वर्तमान धागे का उपयोग करती है?


मैं जो थ्रेड पूल के उपयोग को कॉन्फ़िगर करने के लिए एक संगत तरीका है या नहीं। आदर्श रूप से शेष कोड को बिल्कुल प्रभावित नहीं किया जाना चाहिए। मैं थ्रेड पूल का उपयोग 1 थ्रेड के साथ कर सकता था लेकिन यह काफी नहीं है जो मैं चाहता हूं। कोई विचार?

ExecutorService es = threads == 0 ? new CurrentThreadExecutor() : Executors.newThreadPoolExecutor(threads);

// es.execute / es.submit / new ExecutorCompletionService(es) etc

63
2017-07-05 10:25


मूल




जवाब:


यहां वास्तव में एक सरल है Executor (नहीं ExecutorService, आपको दिमाग) कार्यान्वयन जो केवल वर्तमान धागे का उपयोग करता है। इसे "अभ्यास में जावा कंसुरेंसी" (आवश्यक पढ़ने) से चोरी करना।

public class CurrentThreadExecutor implements Executor {
    public void execute(Runnable r) {
        r.run();
    }
}

ExecutorService एक और विस्तृत इंटरफेस है, लेकिन एक ही दृष्टिकोण के साथ संभाला जा सकता है।


50
2017-07-05 13:59



+1: जैसा कि आप कहते हैं, एक execorService को उसी तरह से संभाला जा सकता है, शायद AbstractExecutorService subclassing द्वारा। - Paul Cager
@ पॉल यप, AbstractExecutorService जाने के रास्ते की तरह दिखता है। - overthink
इतना जरूरी है कि मेरी प्रति काम पर गायब हो गई :-( - Michael Rutherfurd
जावा 8 में आप इसे कम कर सकते हैं Runnable::run - Jon Freedman
लेकिन इस तरह, किसी अन्य धागे से नहीं कहा जा सकता है? - Juude


आप अमरूद का उपयोग कर सकते हैं MoreExecutors.newDirectExecutorService(), या MoreExecutors.directExecutor() अगर आपको जरूरत नहीं है ExecutorService

यदि गुवा समेत बहुत भारी वजन है, तो आप लगभग कुछ अच्छे को कार्यान्वित कर सकते हैं:

public final class SameThreadExecutorService extends ThreadPoolExecutor {
  private final CountDownLatch signal = new CountDownLatch(1);

  private SameThreadExecutorService() {
    super(1, 1, 0, TimeUnit.DAYS, new SynchronousQueue<Runnable>(),
        new ThreadPoolExecutor.CallerRunsPolicy());
  }

  @Override public void shutdown() {
    super.shutdown();
    signal.countDown();
  }

  public static ExecutorService getInstance() {
    return SingletonHolder.instance;
  }

  private static class SingletonHolder {
    static ExecutorService instance = createInstance();    
  }

  private static ExecutorService createInstance() {
    final SameThreadExecutorService instance
        = new SameThreadExecutorService();

    // The executor has one worker thread. Give it a Runnable that waits
    // until the executor service is shut down.
    // All other submitted tasks will use the RejectedExecutionHandler
    // which runs tasks using the  caller's thread.
    instance.submit(new Runnable() {
        @Override public void run() {
          boolean interrupted = false;
          try {
            while (true) {
              try {
                instance.signal.await();
                break;
              } catch (InterruptedException e) {
                interrupted = true;
              }
            }
          } finally {
            if (interrupted) {
              Thread.currentThread().interrupt();
            }
          }
        }});
    return Executors.unconfigurableScheduledExecutorService(instance);
  }
}

69
2018-02-01 04:24





जावा 8 शैली:

Executor e = Runnable::run;


34
2018-01-19 08:00



बिल्कुल गंदी मुझे यह पसंद है। - Rogue


मैंने AbstractExecutorService के आधार पर एक निष्पादक सेवा लिखा था।

/**
 * Executes all submitted tasks directly in the same thread as the caller.
 */
public class SameThreadExecutorService extends AbstractExecutorService {

    //volatile because can be viewed by other threads
    private volatile boolean terminated;

    @Override
    public void shutdown() {
        terminated = true;
    }

    @Override
    public boolean isShutdown() {
        return terminated;
    }

    @Override
    public boolean isTerminated() {
        return terminated;
    }

    @Override
    public boolean awaitTermination(long theTimeout, TimeUnit theUnit) throws InterruptedException {
        shutdown(); // TODO ok to call shutdown? what if the client never called shutdown???
        return terminated;
    }

    @Override
    public List<Runnable> shutdownNow() {
        return Collections.emptyList();
    }

    @Override
    public void execute(Runnable theCommand) {
        theCommand.run();
    }
}

9
2017-12-05 15:20



समाप्त क्षेत्र सिंक्रनाइज़ के साथ संरक्षित नहीं है। - Daneel S. Yaitskov
@ DaneelS.Yaitskov terminated क्षेत्र वास्तव में यहां मौजूद कोड के आधार पर सिंक्रनाइज़ पहुंच से लाभ नहीं उठाएगा। 32-बिट फ़ील्ड पर ऑपरेशंस जावा में परमाणु हैं। - Christopher Schultz
मुझे लगता है कि उपरोक्त में isTerminated () विधि बिल्कुल सही नहीं है क्योंकि iserminated () को केवल तभी वापस करना चाहिए जब कोई वर्तमान कार्य निष्पादित नहीं हो। अमरूद दूसरे चर में कार्यों की संख्या को ट्रैक करता है, जो संभवतः वे लॉक के साथ दोनों चरों की रक्षा क्यों करते हैं। - Jeremy K


वर्तमान थ्रेड में कार्य को चलाने के लिए आप अस्वीकृत एक्सेक्यूशन हैंडलर का उपयोग कर सकते हैं।

public static final ThreadPoolExecutor CURRENT_THREAD_EXECUTOR = new ThreadPoolExecutor(0, 0, 0, TimeUnit.DAYS, new SynchronousQueue<Runnable>(), new RejectedExecutionHandler() {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        r.run();
    }
});

आपको केवल इनमें से किसी एक की आवश्यकता है।


5
2017-07-05 11:21



चतुर! यह कितना सुरक्षित है (ईमानदार सवाल)? क्या किसी कार्य को खारिज करने के लिए कोई तरीका है जहां आप वास्तव में वर्तमान धागे में इसे निष्पादित नहीं करना चाहते हैं? क्या कार्यकर्ता खारिज कर दिया गया है यदि निष्पादक सेवा बंद हो रही है या समाप्त हो गई है? - overthink
चूंकि अधिकतम आकार 0 है, इसलिए प्रत्येक कार्य को खारिज कर दिया जाता है। हालांकि अस्वीकार व्यवहार वर्तमान धागे में चलाना है। यदि कार्य अस्वीकार नहीं किया गया है तो केवल एक समस्या होगी। - Peter Lawrey
ध्यान दें, इस नीति का पहले से ही एक कार्यान्वयन है, स्वयं को परिभाषित करने की कोई आवश्यकता नहीं है java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy। - jtahlborn
अब 0 के अधिकतम पूल आकार के साथ ThreadPoolExecutor बनाने के लिए यह संभव नहीं है। मुझे लगता है कि आकार 0 के ब्लॉकिंग क्यूयू का उपयोग करके व्यवहार को पुन: पेश करना संभव होगा, लेकिन कोई डिफ़ॉल्ट कार्यान्वयन ऐसा करने की अनुमति नहीं देता है। - Axelle Ziegler
जो {code} के कारण संकलित नहीं होगा अगर (corePoolSize <0 || maxPoolSize <= 0 || maxPoolSize <corePoolSize || keepAliveTime <0) {code} java.util में। थ्रेडपूलएक्सएटर (कम से कम openJdk 7) - Bogdan


परीक्षण उद्देश्यों के लिए मुझे "CurrentThreadExecutorService" का उपयोग करना था, हालांकि सभी सुझाए गए समाधान अच्छे थे (विशेष रूप से एक उल्लेख अमरूद रास्ता), मैं पीटर लॉरी के सुझाव के समान कुछ आया था यहाँ

जैसा कि एक्सले ज़िग्लर ने उल्लेख किया है यहाँदुर्भाग्यवश, पीटर का समाधान वास्तव में चेक की वजह से काम नहीं करेगा ThreadPoolExecutor पर maximumPoolSize कन्स्ट्रक्टर पैरामीटर (यानी maximumPoolSize नहीं हो सकता <=0)।

इसे रोकने के लिए, मैंने निम्नलिखित किया:

private static ExecutorService currentThreadExecutorService() {
    CallerRunsPolicy callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
    return new ThreadPoolExecutor(0, 1, 0L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), callerRunsPolicy) {
        @Override
        public void execute(Runnable command) {
            callerRunsPolicy.rejectedExecution(command, this);
        }
    };
}

3
2017-08-28 10:13