2010-07-07 81 views
27

是否有可能爲執行程序執行的任務設置優先級?我在JCIP中發現了一些關於這是可能的陳述,但我找不到任何示例,並且我找不到任何與文檔相關的內容。Java執行程序:如何設置任務優先級?

從JCIP:

執行策略指定 「什麼,在哪裏,何時以及如何」 任務 執行的,其中包括:

  • ...
  • 在哪訂單應執行任務(FIFO,LIFO,優先級訂單)?
  • ...

UPD:我意識到,我問不正是我要問。我真正想要的是:

如何使用/仿真設置線程優先級(即什麼是thread.setPriority())與執行者框架?

回答

48

目前的the Executor interface唯一具體的實現是the ThreadPoolExecutorthe ScheduledThreadpoolExecutor

而不是使用公共設施/工廠類Executors的,你應該創建使用構造一個實例。

您可以將BlockingQueue傳遞給ThreadPoolExecutor的構造函數。

BlockingQueue的一個實現the PriorityBlockingQueue允許您將一個Comparator傳遞給構造函數,這樣您可以決定執行的順序。

+3

+1的PriorityBlockingQueue是要走的路。您可以實現比較器或將任務自己設置爲Comparable。 – 2010-07-08 00:47:24

+2

本文是一個很好的參考資料:http://binkley.blogspot.fr/2009/04/jumping-work-queue-in-executor.html – Snicolas 2013-06-04 08:43:52

+0

我的解決方案按優先順序排列任務,但保留相同優先級的提交順序: http://stackoverflow.com/a/42831172/1386911 – 2017-03-16 10:26:45

0

請注意,setPriority(..)一般不會在Linux下工作。請參閱以下鏈接的全部細節:

+2

評論有意見;答案是答案。評論不是答案。答案不是評論。如果它不回答被問到的問題,那實際上是一個評論。 – 2012-09-30 19:02:37

+0

+1 @尼克 - 哈哈,喜歡它!爲什麼用一個詞,當你可以使用一個冗長,單調的評論。好點(好臉色)。 – TedTrippin 2013-04-19 14:01:24

2

您可以指定在ThreadPoolExecutor構造函數(或Executors工廠法)ThreadFactory。這使您可以爲執行程序提供給定線程優先級的線程。

要獲得不同作業的不同線程優先級,您需要將它們發送給具有不同線程工廠的執行程序。

30

這裏的想法是在執行器中使用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 
+0

雖然*接受答案*確實回答了這個問題,這個提供了一個工作解決方案。非常感謝。 – m02ph3u5 2015-10-06 16:13:48

+0

感謝您的回答。是否可以在ExecutorCompletionService中使用這種方法?我嘗試傳入ExecutorCompletionService構造函數中的ExecutorService對象,但結果無法傳遞給比較器中的PriorityFuture。 – Arash 2015-11-27 23:46:55

+0

我在我的機器上測試過。這是不正確的。在我的機器上,執行3之前執行了72,這顯然是錯誤的。 – 2016-11-03 14:43:53

0

只是想我的貢獻位加入討論。我已經實現了這個ReorderingThreadPoolExecutor用於一個非常具體的目的,它能夠在需要時顯式地將執行者的BlockingQueue(在這種情況下是LinkedBlockingDeque)帶到前面,而不必處理優先級(這可能導致死鎖並且是無論如何,固定)。

我正在使用它來管理(在Android應用程序內)的情況下,我必須下載許多圖像顯示在長列表視圖。每當用戶快速向下滾動時,執行程序隊列就會充滿圖像下載請求:通過移動隊列頂部的最新隊列,我在加載實際在屏幕上的圖像方面取得了更好的性能,延遲了下載那些稍後可能需要的。請注意,我使用內部併發映射鍵(可以像圖像URL字符串一樣簡單)將任務添加到執行程序,以便稍後可以檢索它們以進行重新排序。

還有很多其他方法可以做到這一點,也許它過於複雜,但它工作正常,而且他的Android SDK中的Facebook在其自己的工作線程隊列中也做了類似的事情。

隨意看看代碼,給我的建議,這是一個Android項目內,但剝離了幾個日誌和註解會使類純Java 6

0

您可以實現自己的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; 
    } 
}