سؤال

هل هناك إمكانية لتحديد الأولوية للمهام التي ينفذها المنفذون؟ لقد وجدت بعض العبارات في JCIP حول هذا ممكن ، لكن لا يمكنني العثور على أي مثال ولا يمكنني العثور على أي شيء مرتبط في المستندات.

من JCIP:

تحدد سياسة التنفيذ "ماذا وأين ومتى وكيف" تنفيذ المهام ، بما في ذلك:

  • ...
  • بأي ترتيب يجب تنفيذ المهام (FIFO ، LIFO ، ترتيب الأولويات)?
  • ...

UPD: أدركت أنني لم أسأل بالضبط ما أردت أن أسأله. ما أردته حقًا هو:

كيفية استخدام/محاكاة إعداد المواضيع ذات الأولوية (أي ما كان thread.setPriority()) مع إطار المنفذين؟

هل كانت مفيدة؟

المحلول

حاليا التطبيقات الملموسة الوحيدة ل واجهة المنفذ نكون througpoolexecutor و المجدول

بدلاً من استخدام فئة الأداة المساعدة / المصنع المنفذون, ، يجب عليك إنشاء مثيل باستخدام مُنشئ.

يمكنك تمرير أ blockingqueue إلى مُنشئات threadpoolexecutor.

أحد تطبيقات blockingqueue ، و priorityblockingqueue يتيح لك تمرير مقارنة إلى مُنشئ ، وبهذه الطريقة تمكنك من تحديد ترتيب التنفيذ.

نصائح أخرى

الفكرة هنا هي استخدام priorityblockingqueue في المنفذ. لهذا:

  • إنشاء مقارنة من شأنها أن تقارن مستقبلنا.
  • إنشاء وكيل للمستقبل ليحمل أولوية.
  • تجاوز "NewTaskfor" من أجل لف كل مستقبل في وكيلنا.

تحتاج أولاً إلى الاحتفاظ بالولايات في مستقبلك:

    class PriorityFuture<T> implements RunnableFuture<T> {

    private RunnableFuture<T> src;
    private int priority;

    public PriorityFuture(RunnableFuture<T> other, int priority) {
        this.src = other;
        this.priority = priority;
    }

    public int getPriority() {
        return priority;
    }

    public boolean cancel(boolean mayInterruptIfRunning) {
        return src.cancel(mayInterruptIfRunning);
    }

    public boolean isCancelled() {
        return src.isCancelled();
    }

    public boolean isDone() {
        return src.isDone();
    }

    public T get() throws InterruptedException, ExecutionException {
        return src.get();
    }

    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        return src.get();
    }

    public void run() {
        src.run();
    }
}

بعد ذلك ، تحتاج إلى تحديد المقارنة التي من شأنها فرز العقود الآجلة ذات الأولوية بشكل صحيح:

class PriorityFutureComparator implements Comparator<Runnable> {
    public int compare(Runnable o1, Runnable o2) {
        if (o1 == null && o2 == null)
            return 0;
        else if (o1 == null)
            return -1;
        else if (o2 == null)
            return 1;
        else {
            int p1 = ((PriorityFuture<?>) o1).getPriority();
            int p2 = ((PriorityFuture<?>) o2).getPriority();

            return p1 > p2 ? 1 : (p1 == p2 ? 0 : -1);
        }
    }
}

بعد ذلك ، لنفترض أن لدينا وظيفة مطولة مثل هذا:

class LenthyJob implements Callable<Long> {
    private int priority;

    public LenthyJob(int priority) {
        this.priority = priority;
    }

    public Long call() throws Exception {
        System.out.println("Executing: " + priority);
        long num = 1000000;
        for (int i = 0; i < 1000000; i++) {
            num *= Math.random() * 1000;
            num /= Math.random() * 1000;
            if (num == 0)
                num = 1000000;
        }
        return num;
    }

    public int getPriority() {
        return priority;
    }
}

ثم من أجل تنفيذ هذه الوظائف في الأولوية ، سيبدو الرمز:

public class TestPQ {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        int nThreads = 2;
        int qInitialSize = 10;

        ExecutorService exec = new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
                new PriorityBlockingQueue<Runnable>(qInitialSize, new PriorityFutureComparator())) {

            protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
                RunnableFuture<T> newTaskFor = super.newTaskFor(callable);
                return new PriorityFuture<T>(newTaskFor, ((LenthyJob) callable).getPriority());
            }
        };

        for (int i = 0; i < 20; i++) {
            int priority = (int) (Math.random() * 100);
            System.out.println("Scheduling: " + priority);
            LenthyJob job = new LenthyJob(priority);
            exec.submit(job);
        }
    }
}

هذا هو الكثير من التعليمات البرمجية ولكن هذا هو ما يقرب من الطريقة الوحيدة التي يمكن تحقيق ذلك.

على الجهاز الخاص بي ، يشبه الإخراج ما يلي:

Scheduling: 39
Scheduling: 90
Scheduling: 88
Executing: 39
Scheduling: 75
Executing: 90
Scheduling: 15
Scheduling: 2
Scheduling: 5
Scheduling: 24
Scheduling: 82
Scheduling: 81
Scheduling: 3
Scheduling: 23
Scheduling: 7
Scheduling: 40
Scheduling: 77
Scheduling: 49
Scheduling: 34
Scheduling: 22
Scheduling: 97
Scheduling: 33
Executing: 2
Executing: 3
Executing: 5
Executing: 7
Executing: 15
Executing: 22
Executing: 23
Executing: 24
Executing: 33
Executing: 34
Executing: 40
Executing: 49
Executing: 75
Executing: 77
Executing: 81
Executing: 82
Executing: 88
Executing: 97

يمكنك تنفيذ ThreadFactory الخاص بك وتعيينه داخل ThreadPoolexecutor مثل هذا:

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, numOfWorkerThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
threadPool.setThreadFactory(new OpJobThreadFactory(Thread.NORM_PRIORITY-2));

حيث يشبه OpjobThreadFactory ما يلي:

public final static class OpJobThreadFactory implements ThreadFactory {
   private int priority;
   private boolean daemon;
   private final String namePrefix;
   private static final AtomicInteger poolNumber = new AtomicInteger(1);
   private final AtomicInteger threadNumber = new AtomicInteger(1);

   public OpJobThreadFactory(int priority) {
      this(priority, true);
   }

   public OpJobThreadFactory(int priority, boolean daemon) {
      this.priority = priority;
      this.daemon = daemon;
      namePrefix = "jobpool-" +poolNumber.getAndIncrement() + "-thread-";
   }

   @Override
   public Thread newThread(Runnable r) {
      Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
      t.setDaemon(daemon);
      t.setPriority(priority);
      return t;
   }
}

يمكنك استخدام ThreadPoolexecutor مع قائمة انتظار عرقلة الأولويةكيفية تنفيذ priorityblockingqueue مع threadpoolexecutor والمهام المخصصة

يمكنك تحديد أ ThreadFactory في ال ThreadPoolExecutor مُنشئ (أو Executors طريقة المصنع). يتيح لك ذلك توفير مؤشرات ترابط ذات أولوية خيط معينة للمنفذ.

للحصول على أولويات مختلفة للموضوع لوظائف مختلفة ، ستحتاج إلى إرسالها إلى المنفذين مع مصانع خيوط مختلفة.

يرجى العلم أن setPriority (..) عادة ما يفعل ليس العمل تحت Linux. راجع الروابط التالية للحصول على التفاصيل الكاملة:

فقط أريد إضافة جزء من مساهمتي في هذه المناقشة. لقد قمت بتنفيذ هذا reorderingThreadPoolexecutor لغرض محدد للغاية ، والذي يمكن أن يكون قادرًا على إحضاره صراحة إلى مقدمة المنفذ الخاص بـ Executor (في هذه الحالة LinkedBlockingDeque) كلما أردت وبدون الاضطرار إلى التعامل مع الأولويات (والتي يمكن أن تؤدي إلى طريق مسدود ، على أي حال ، ثابتة).

أنا أستخدم هذا لإدارة (داخل تطبيق Android) الحالة التي يتعين علي فيها تنزيل العديد من الصور التي يتم عرضها في طريقة عرض قائمة طويلة. كلما قام المستخدم بالتمرير لأسفل بسرعة ، يتم إغراق قائمة انتظار Executor من طلبات تنزيل الصور: من خلال نقل أحدث تلك الموجودة في الجزء العلوي من قائمة الانتظار ، لقد حققت عروضًا أفضل بكثير في تحميل الصور الموجودة فعليًا على الشاشة تلك التي من المحتمل أن تحتاج لاحقًا. لاحظ أنني أستخدم مفتاح خريطة متزامن داخلي (والذي يمكن أن يكون بسيطًا مثل سلسلة عنوان URL للصور) لإضافة المهام إلى المنفذ حتى أتمكن من استردادها لاحقًا لإعادة الترتيب.

كانت هناك العديد من الطرق الأخرى لفعل الشيء نفسه وربما يتم تعويضه بشكل مفرط ، لكنه يعمل بشكل جيد وأيضًا Facebook في Android SDK الخاص به يقوم بشيء مماثل في قائمة انتظار خيوط العمل الخاصة به.

لا تتردد في إلقاء نظرة على الكود وإعطائي اقتراحات ، فهو داخل مشروع Android ولكن تجريد بعض السجلات والشروح من شأنه أن يجعل Class Pure Java 6.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top