Prioritné plánovanie úloh v Jave
1. Úvod
V prostredí s viacerými vláknami niekedy musíme naplánovať úlohy na základe vlastných kritérií, nielen na čas potrebný na ich vytvorenie.
Pozrime sa, ako to môžeme v Jave dosiahnuť - pomocou a Priorita blokovania.
2. Prehľad
Povedzme, že máme pracovné miesta, ktoré chceme vykonávať na základe ich priority:
verejná trieda Job implementuje Runnable {private String jobName; súkromná JobPriority jobPriority; @Override public void run () {System.out.println ("Job:" + jobName + "Priority:" + jobPriority); Závit. Spánok (1 000); // na simuláciu skutočného času vykonania} // štandardní zadávatelia a obstarávatelia}
Na demonštračné účely tlačíme názov úlohy a prioritu do súboru run () metóda.
Tiež sme pridali spánok () aby sme simulovali dlhšie bežiacu prácu; počas vykonávania úlohy sa v prioritnom fronte nahromadí viac úloh.
Nakoniec JobPriority je jednoduchý výčet:
verejné enum JobPriority {VYSOKÉ, STREDNÉ, NÍZKE}
3. Vlastné Komparátor
Musíme napísať komparátor definujúci naše vlastné kritériá; a v prostredí Java 8 je to triviálne:
Comparator.comparing (Job :: getJobPriority);
4. Prioritný plánovač úloh
Po dokončení všetkých nastavení teraz implementujme jednoduchý plánovač úloh - ktorý na hľadanie úloh v Priorita blokovania a vykoná ich:
verejná trieda PriorityJobScheduler {private ExecutorService priorityJobPoolExecutor; private ExecutorService priorityJobScheduler = Executors.newSingleThreadExecutor (); private PriorityBlockingQueue priorityQueue; public PriorityJobScheduler (Integer poolSize, Integer queueSize) {priorityJobPoolExecutor = Executors.newFixedThreadPool (poolSize); priorityQueue = new PriorityBlockingQueue (queueSize, Comparator.comparing (Job :: getJobPriority)); priorityJobScheduler.execute (() -> {while (true) {try {priorityJobPoolExecutor.execute (priorityQueue.take ());} catch (InterruptedException e) {// výnimka vyžaduje špeciálne zachádzanie;}}}); } public void scheduleJob (Job job) {priorityQueue.add (job); }}
Kľúčom je vytvorenie inštancie Priorita blokovania z Job typ s vlastným komparátorom. Ďalšia úloha, ktorá sa má vykonať, sa vyberie z frontu pomocou vziať () metóda, ktorá načíta a odstráni hlavu frontu.
Kód klienta teraz musí jednoducho zavolať na scheduleJob () - ktorý pridá úlohu do frontu. The priorityQueue.add () zařadí úlohu na vhodné miesto v porovnaní s existujúcimi úlohami vo fronte pomocou JobExecutionComparator.
Upozorňujeme, že skutočné úlohy sa vykonávajú pomocou samostatnej úlohy ExecutorService s vyhradeným fondom vlákien.
5. Ukážka
Na záver je tu krátka ukážka plánovača:
private static int POOL_SIZE = 1; private static int QUEUE_SIZE = 10; @Test public void whenMultiplePriorityJobsQueued_thenHighestPriorityJobIsPicked () {Job job1 = new Job ("Job1", JobPriority.LOW); Job job2 = new Job ("Job2", JobPriority.MEDIUM); Job job3 = new Job ("Job3", JobPriority.HIGH); Job job4 = new Job ("Job4", JobPriority.MEDIUM); Job job5 = new Job ("Job5", JobPriority.LOW); Job job6 = new Job ("Job6", JobPriority.HIGH); PriorityJobScheduler pjs = nový PriorityJobScheduler (POOL_SIZE, QUEUE_SIZE); pjs.scheduleJob (job1); pjs.scheduleJob (job2); pjs.scheduleJob (job3); pjs.scheduleJob (job4); pjs.scheduleJob (job5); pjs.scheduleJob (job6); // vyčistiť }
Aby sme predviedli, že úlohy sú vykonávané v poradí podľa priority, ponechali sme si POOL_SIZE ako 1, aj keď QUEUE_SIZE je 10. Poskytujeme úlohy s rôznou prioritou plánovaču.
Tu je ukážkový výstup, ktorý sme dostali pre jeden z cyklov:
Práca: Job3 Priorita: VYSOKÁ Job: Job6 Priorita: VYSOKÁ Job: Job4 Priorita: STREDNÁ Job: Job2 Priorita: STREDNÁ Job: Job1 Priorita: LOW Job: Job5 Priorita: LOW
Výstup sa môže v jednotlivých behoch líšiť. Nikdy by sme však nemali mať prípad, keď sa úloha s nižšou prioritou vykoná, aj keď front obsahuje úlohu s vyššou prioritou.
6. Záver
V tomto rýchlom návode sme videli, ako na to Priorita blokovania možno použiť na vykonávanie úloh vo vlastnom poradí priorít.
Ako obvykle, zdrojové súbory nájdete na GitHub.