2010-07-07 13 views
27

Có khả năng đặt ưu tiên cho các tác vụ được thực hiện bởi các công tố viên không? Tôi đã tìm thấy một số tuyên bố trong JCIP về điều đó có thể nhưng tôi không thể tìm thấy bất kỳ ví dụ nào và tôi không thể tìm thấy bất kỳ điều gì có liên quan trong tài liệu.Java Executors: làm thế nào tôi có thể thiết lập ưu tiên nhiệm vụ?

Từ JCIP:

Một chính sách thực hiện quy định cụ thể "gì, ở đâu, khi nào và như thế nào" của nhiệm vụ thực hiện, bao gồm:

  • ...
  • Trong những gì các nhiệm vụ đặt hàng nên được thực hiện (FIFO, LIFO, thứ tự ưu tiên)?
  • ...

UPD: Tôi nhận ra rằng tôi yêu cầu không chính xác những gì tôi muốn hỏi. Điều tôi thực sự muốn là:

Cách sử dụng/mô phỏng mức độ ưu tiên của chủ đề cài đặt (tức là thread.setPriority()) với khung công tác điều hành là gì?

Trả lời

48

Hiện nay việc triển khai cụ thể duy nhất của the Executor interfacethe ThreadPoolExecutorthe ScheduledThreadpoolExecutor

Thay vì sử dụng các lớp tiện ích/nhà máy Executors, bạn nên tạo một thể hiện sử dụng một constructor.

Bạn có thể chuyển số BlockingQueue cho các nhà thầu của ThreadPoolExecutor.

Một trong những triển khai của BlockingQueue, the PriorityBlockingQueue cho phép bạn chuyển một Trình so sánh tới một hàm tạo, theo cách đó cho phép bạn quyết định thứ tự thực thi.

+3

+1 PriorityBlockingQueue là con đường để đi. Bạn có thể thực hiện một Comparator hoặc tự thực hiện các nhiệm vụ Comparable. –

+2

Bài viết này là một tài liệu tham khảo tuyệt vời: http://binkley.blogspot.fr/2009/04/jumping-work-queue-in-executor.html – Snicolas

+0

Lệnh giải quyết tác vụ của tôi theo mức độ ưu tiên, nhưng vẫn giữ nguyên thứ tự gửi ở cùng mức ưu tiên: http://stackoverflow.com/a/42831172/1386911 –

0

Xin lưu ý rằng setPriority (..) thường không không làm việc dưới Linux. Xem các liên kết sau đây để biết chi tiết đầy đủ:

+2

Nhận xét là nhận xét; câu trả lời là câu trả lời. Nhận xét không phải là câu trả lời. Câu trả lời không phải là bình luận. Nếu nó không trả lời câu hỏi đang được hỏi, đó là, trên thực tế, một bình luận. –

+0

+1 @Nick - Ha ha, thích nó!Tại sao lại sử dụng một từ khi bạn có thể sử dụng một nhận xét dài dòng, đầy lúng túng. Điểm tốt và tốt (thực sự). – TedTrippin

2

Bạn có thể chỉ định một ThreadFactory trong ThreadPoolExecutor constructor (hoặc phương pháp Executors nhà máy). Điều này cho phép bạn cung cấp các luồng của ưu tiên luồng cho trước cho trình thực hiện.

Để nhận các ưu tiên luồng khác nhau cho các công việc khác nhau, bạn cần gửi chúng đến các nhà điều hành với các nhà máy luồng khác nhau.

30

Ý tưởng ở đây là sử dụng PriorityBlockingQueue trong trình thực thi. Đối với điều này:

  • Tạo một so sánh so sánh tương lai của chúng tôi.
  • Tạo proxy cho Tương lai để giữ mức độ ưu tiên.
  • Ghi đè 'newTaskFor' để bao bọc mọi tương lai trong proxy của chúng tôi.

Trước tiên, bạn cần phải giữ ưu tiên về tương lai của bạn:

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

Tiếp theo, bạn cần phải xác định so sánh rằng sẽ sắp xếp một cách chính xác tương lai ưu tiên:

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

Tiếp theo chúng ta hãy giả sử chúng ta có một công việc dài như thế này:

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

Sau đó, để thực hiện các công việc này, mã sẽ trông giống như sau:

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

Đây là mã rất nhiều nhưng đó là cách duy nhất có thể thực hiện được.

Trên máy tính của tôi đầu ra là như sau:

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 
+0

Trong khi câu trả lời * chấp nhận * trả lời câu hỏi, câu hỏi này cung cấp giải pháp làm việc. Cảm ơn rất nhiều. – m02ph3u5

+0

Cảm ơn câu trả lời của bạn. Có thể sử dụng phương pháp này với ExecutorCompletionService không? Tôi đã cố gắng để vượt qua trong đối tượng ExecutorService của bạn trong các nhà xây dựng ExecutorCompletionService nhưng kết quả không thể được đúc để PriorityFuture trong so sánh. – Arash

+0

Tôi đã thử nghiệm trên máy của mình. Nó không đúng. Trên máy của tôi, tôi đã thi hành 72 trước khi thi hành 3, điều đó hoàn toàn sai. –

0

Chỉ muốn thêm chút của tôi về đóng góp cho cuộc thảo luận này. Tôi đã thực hiện điều này ReorderingThreadPoolExecutor cho một mục đích rất cụ thể, có thể đưa rõ ràng đến phía trước BlockingQueue của người thi hành (trong trường hợp này là LinkedBlockingDeque) bất cứ khi nào tôi muốn và không phải đối phó với các ưu tiên (có thể dẫn đến deadlocks và , anyway, cố định).

Tôi đang sử dụng tính năng này để quản lý (bên trong ứng dụng Android) trường hợp tôi phải tải xuống nhiều hình ảnh được hiển thị trong chế độ xem danh sách dài. Bất cứ khi nào người dùng cuộn xuống một cách nhanh chóng, hàng đợi của trình điều khiển bị tràn ngập các yêu cầu tải xuống hình ảnh: bằng cách di chuyển các ảnh mới nhất lên đầu hàng đợi, tôi đã đạt được hiệu suất tốt hơn nhiều trong việc tải các hình ảnh thực sự trên màn hình, trì hoãn việc tải xuống những thứ có thể sẽ cần sau này. Lưu ý rằng tôi sử dụng khóa bản đồ đồng thời bên trong (có thể đơn giản như chuỗi URL hình ảnh) để thêm các tác vụ vào trình thực thi để tôi có thể truy xuất chúng sau này để sắp xếp lại.

Đã có nhiều cách khác để làm như vậy và có thể nó quá phức tạp, nhưng nó hoạt động tốt và cũng Facebook trong SDK Android của mình đang làm một cái gì đó tương tự trong hàng đợi chủ đề làm việc của mình.

Hãy thoải mái để có một cái nhìn vào mã và đưa cho tôi đề nghị, đó là bên trong một dự án Android nhưng tước một vài bản ghi và chú thích sẽ làm cho lớp tinh khiết Java 6.

0

Bạn có thể thực hiện ThreadFactory của riêng bạn và thiết lập nó trong vòng ThreadPoolExecutor như thế này:

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

nơi OpJobThreadFactory của tôi trông giống như sau:

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