এমন কোনও এক্সিকিউটর সার্ভিস রয়েছে যা বর্তমান থ্রেড ব্যবহার করে?


94

আমি পরে যা করছি তা কোনও থ্রেড পুলের ব্যবহারটি কনফিগার করার একটি সামঞ্জস্যপূর্ণ উপায়। আদর্শভাবে বাকি কোডগুলি মোটেই প্রভাবিত হওয়া উচিত নয়। আমি 1 থ্রেড সহ একটি থ্রেড পুল ব্যবহার করতে পারতাম তবে এটি আমার পছন্দসই নয়। কোন ধারনা?

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

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

উত্তর:


70

এখানে একটি বাস্তব সরল Executor( ExecutorServiceআপনি মনে করবেন না) বাস্তবায়ন যা কেবলমাত্র বর্তমান থ্রেড ব্যবহার করে। এটি "অনুশীলনে জাভা কনকুরেন্সি" (প্রয়োজনীয় পড়া) থেকে চুরি করা।

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

ExecutorService আরও বিস্তৃত ইন্টারফেস, তবে একই পদ্ধতির সাহায্যে পরিচালনা করা যেতে পারে।


4
+1: আপনি যেমনটি বলেছেন, একজন এক্সিকিউটর সার্ভিসও একইভাবে পরিচালনা করা যেতে পারে, সম্ভবত অ্যাবস্ট্রাক্ট এক্সেকিউটারসেবা সাবস্ক্লাস করে।
পল কেগার

@ পল ইয়েপ, AbstractExecutorServiceদেখতে যাওয়ার মতো মনে হচ্ছে।
চিন্তা কোরো

15
জাভা 8-এ আপনি এটিকে কেবল হ্রাস করতে পারবেনRunnable::run
জন ফ্রিডম্যান

@ জুয়েড এটি সর্বদা থ্রেডে চালিত হবে যা নির্বাহককে কল করে।
গুস্তাভ কার্লসন

এক্সিকিউটর () এর মধ্যে থেকে আরও কাজ শিডিউল করতে সক্ষম হওয়ার জন্য কি একই থ্রেড এক্সিকিউটারের বিন্দু নয়? এই উত্তরটি করবে না। এটির সন্তুষ্ট করে এমন কোনও উত্তর আমি পাই না।
হেলিক্স

82

আপনি পেয়ারা ব্যবহার করতে পারেন 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);
  }
}

4
অ্যান্ড্রয়েডের জন্য, এটি এক্সিকিউটরস.উনফনফিউরেবলএক্সেকিউটার সার্ভিস (উদাহরণ) ফিরে আসবে;
ম্যারাগিউস

যদি আমরা ব্যবহার করি সমস্তই বর্তমান থ্রেড হয় তবে সিঙ্ক্রোনাইজেশন আদিম কেন? কেন লাচ?
হেলিক্স

@ হেলিক্স ল্যাচটির প্রয়োজন কারণ কাজটি একই থ্রেডে কাজ করা হলেও এটি যে কাজটি যুক্ত করেছে, কোনও থ্রেড নির্বাহককে বন্ধ করে দিতে পারে।
নামশুব রাইটার

64

জাভা 8 স্টাইল:

Executor e = Runnable::run;


8
একেবারে নোংরা। আমি এটা ভালোবাসি.
বিশৃঙ্খল

এ সম্পর্কে নোংরামি কি? এটি মার্জিত :)
lpandzic

4
এটি সর্বোত্তম ধরণের অশ্লীল @ ইপানডিজিক, এটি অস্বাভাবিক এবং সংঘাতযুক্ত।
কুফল

12

আমি একটি ExecutorServiceউপর ভিত্তি করে লিখেছি 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();
    }
}

সমাপ্ত ক্ষেত্র সিঙ্ক্রোনাইজড দিয়ে সুরক্ষিত নয়।
দানিল ইয়েতস্কোভ

4
@ ড্যানিয়েলস.ইয়েটস্কভ terminatedক্ষেত্রটি এখানে যে কোডটি রয়েছে তা ভিত্তিক সিঙ্ক্রোনাইজড অ্যাক্সেস থেকে উপকৃত হবে না। জাভাতে 32-বিট ক্ষেত্রগুলিতে অপারেশনগুলি পারমাণবিক।
ক্রিস্টোফার শুল্টজ

আমি মনে করি উপরের আইসটারমিনেটেড () পদ্ধতিটি বেশ সঠিক নয় কারণ ইস্টার্মিনেটেড () বর্তমানে কোনও কার্যকর সম্পাদনকারী কার্য না থাকলে কেবল সত্য প্রত্যাশিত। পেয়ারা অন্য ভেরিয়েবলের কাজের সংখ্যা ট্র্যাক করে, সম্ভবত তারা লক দিয়ে উভয় ভেরিয়েবলকে সুরক্ষা দেয়।
জেরেমি কে

7

আপনি বর্তমান থ্রেডে টাস্কটি চালাতে রিজেক্টএক্সিকিউশনহ্যান্ডলারটি ব্যবহার করতে পারেন।

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

আপনার এগুলির মধ্যে কেবল একটি প্রয়োজন।


চালাক! এটি (সৎ প্রশ্ন) কতটা নিরাপদ? কোনও কাজকে প্রত্যাখ্যান করার কোনও উপায় আছে যেখানে আপনি বর্তমান থ্রেডে বাস্তবে এটি সম্পাদন করতে চান না? যদি এক্সিকিউটর সার্ভিস বন্ধ বা বন্ধ হয় তবে কাজগুলি কি প্রত্যাখ্যান করা হবে?
চিন্তা কোরো

যেহেতু সর্বোচ্চ আকার 0 হয় তাই প্রতিটি কাজ প্রত্যাখ্যান করা হয়। তবে প্রত্যাখ্যাত আচরণটি বর্তমান থ্রেডে চালানো। যদি কাজটি প্রত্যাখ্যান না করা হয় কেবল তখনই সমস্যা হবে।
পিটার লরে

8
দ্রষ্টব্য, ইতিমধ্যে এই নীতিটির একটি বাস্তবায়ন রয়েছে, আপনার নিজের সংজ্ঞা দেওয়ার দরকার নেই java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
jtahlorn

7
সর্বোচ্চ ০ আকারের পুলের থ্রেডপুলএক্সিকিউটর তৈরি করা আর সম্ভব নয় I আমি অনুমান করি যে 0 আকারের একটি ব্লকিংকিউ ব্যবহার করে আচরণটি পুনরুত্পাদন করা সম্ভব হবে, তবে কোনও ডিফল্ট বাস্তবায়ন এটির অনুমতি দেয় বলে মনে হয় না।
অ্যাক্সেল জিগেলার

যা {কোড to এর কারণে সংকলিত হবে না যদি (কোরপুলসাইজ <0 || সর্বোচ্চপুলসাইজ <= 0 || সর্বাধিক পুলসাইজ <কোরপুলসাইজ || কেপলাইভটাইম <0) {কোড} in java.util.ThreadPoolExecutor (কমপক্ষে openJdk 7)
বোগদান

7

পরীক্ষার উদ্দেশ্যে আমাকে একই "কারেন্টথ্রেডএ্যাক্সেকিউটারস সার্ভিস" ব্যবহার করতে হয়েছিল এবং যদিও সমস্ত প্রস্তাবিত সমাধানগুলি দুর্দান্ত ছিল (বিশেষত এককটি পেয়ারা পথের উল্লেখ করে ), আমি পিটার লরিকে এখানে যে পরামর্শ দিয়েছিল তার অনুরূপ কিছু নিয়ে এসেছি

Axelle Ziegler উল্লেখ হিসাবে এখানে , দুর্ভাগ্যবশত পিটার্স সমাধান আসলে না চেক চালু কারণ কাজ করবে 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);
        }
    };
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.