uio--WebPageMain-Module

JAVA-B4 Parallel Computing (Parallelism) Parallelism Multithreading

Klassische Threads Threads & Runnables Overview Thread (Begriff) DruckThread DruckRunnable ThreadDemo Output Thread Lifecycle Overview start() run() join() stop()? StartRunJoinDemo Example Von allein endende Threads Threads mit while(criteria) Daemon-Threads Overview ThreadDaemonDemo Daemon (Summary) Thread-Priority Overview t.setPriority(..) MachineThread Klasse (Example) ThreadPriorityDemo (Example) Thread Notification Grundlagen wait notify notifyAll sleep sleep vs. wait Thread Notification Demo sychronized(monitor) Notification/Monitor Zusammenfassung

Concurrent API Vom Thread zur Concurrent API Was ist Concurrency? Was ist Concurrency? Problemstellungen bei herkömmlichen Threads Features der Concurrent API Warum: Bedeutung des Umstiegs Themenüberblick Technischer Hintergrund Thread.sleep(0, 500_000) System.nanoTime()

Executors (Übersicht) #310 ExecutorService (Page) Begriffsbestimmung Excetutor .execute() ExecutorService (Begriff) ExecutorService Interface Methoden Mehrere Callables und Runnables auf einmal starten Kontrolliertes Beenden Executors-Utilily Klasse newCachedThreadPool() newSingleThreadExecutor() newFixedThreadPool(int nThreads) newWorkStealingPool() newScheduledThreadPool(int corePoolSize) Beispiel ForkJoinPool, RecursiveTask, Executors Example#09 A | B1,B2,B3 | C mit Summenbildung. Executor vs. ExecutorService Example#10 Executors.newFixedThreadPool(2) Beispiel Zusammenfassung Executors

Callable, Future #330 Callable Future (Begriff) Callable Interface (Begriff) Begriff Callable erzeugen Callable verwenden Future Beispiel

Future-Listen mit invokeAll Was sind Future-Listen? Wie erzeuge ich Future-Listen? Wann blockt eine Future-Liste? Beispiel mit 12 Callables in 4 Gruppen

Executors (#350) @! Bis auf Hinweis doppelt Overview Executor (Begriff) ExecutorService (Begriff) Executors.new~ Factory Methoden Executors für ThreadPoolExecutor mit fixed Pool

ScheduledExecutorService ScheduledExecutorService Superklasse ExecutorService schedule(*) scheduleAtFixedRate(*) scheduleWithFixedDelay(*) ScheduledExecutorService (xmpl) ProductClock(Main, Bsp.) AbstractMachine** AbstractMaterial** Coal/Iron/Steel** Coal-/Iron-/Steel-Machine** Material** ProductionBus-Machine** Storage T**
ThreadPoolExecutor (Detail) Executor Implementierung ThreadPoolExecutor (Term) ThreadPoolExecutor Beispiele "FixedSizeExecutorExample" EXAMPLE C20 "CachedExecutorExample" EXAMPLE C21 SynchronousQueue "ScheduledExecutorExample" EXAMPLE C22 "CustomSingleThreadExecutorRunnableComponent" EXAMPLE C23 "CustomPolicyRejectedExecutorExample" EXAMPLE C24 "PrioritizedCombinerRunnableComponent" EXAMPLE C30 "BufferingRejectedTasksExample" EXAMPLE C31 Java RejectedExecutionHandler ThreadPoolExecutor FAQ

Synchronizer Synchronizer (overview) Synchronizer Begriff CountDownLatch CountDownLatch Example CyclicBarrier CyclicBarrier Example (@Zeit ausgeben!) Phaser Phaser Example(@Erl!) Exchanger Exchanger ping/pong Semaphore CompletableFuture async!!! SemaphoreCompletableFutureDemo (@!?)

Monitoring JMX ThreadPoolExecutor "live" überwachen getActiveCount() getPoolSize() getCompletedTaskCount() getQueue().size()

Concurrency Example:DeterministicCopy @todo FILE LINK FEHLT! Example:NonDeterministicCopy @todo FILE LINK FEHLT!

Kapitel java.util.concurrent.Flow @!fehltReactive Flow @!fehltPublisher TSubscriber TSubscription TProcressor TProcressor T

Overview

Concurrent Synchronizer| Overview

Die Klasse ThreadPoolExecutor ist die zentrale Implementierungsklasse für die Interfaces Executor, ExecutorService und ScheduledExecutorService und zugleich die Basisklasse für den ScheduledThreadPoolExecutor.

ThreadPoolExecutor

Synchronizer

Concurrent Synchronizer | Begriffsbestimmung

Ein Concurrent Synchronizerl

java.util.concurrent beinhaltet eine ganze Reihe von Synchronizern. All diese Synchrozier sind im Kern darauf spezialisiert, die Zusammenarbeit oder auch die Abstimmung zwischen verschiedenen Threads zu ermöglichen.

Man bezeichnet das auch als "Concurrency Coordination" oder Koordination im Bereich der nebenläufigen Programmierung.


Synchronizer-Kategorie
├─ CountDownLatch Countdown für mehrere Threads
├─ CyclicBarrier Barriere für Gruppen-Threads
├─ Phaser Phasenbasierte Koordination
├─ Exchanger Daten austauschen zwischen zwei Threads
└─ Semaphore Begrenzte Zugriffsanzahl
 

Abbildung: Diagramm mit Übersicht von Synchronizern aus java.util.concurrent.

(ContentInstance snewmedia_java_concurrent_synchronizers)

Warten auf mehrere Events: CountDownLatch.

Gruppensynchronisation: CyclicBarrier. Es gibt nur eine Barriere und eine fixe Anzahl von Threads.

Mehrere Phasen, flexibel: Phaser.

Gegenseitiger Austausch: Exchanger mit Typparameter T

Ressourcenzugriff regeln: Semaphore. Ermöglich es, dass für den Pool, welchen die Semaphore verwaltet, z. B. nur 2 Threads gleichzeitig arbeiten dürfen.

CountDownLatch

Synchronizers | CountDownLatch

Der CountDownLatch Synchronizer erfasst alle Tasks und führt Sie in einer beliebigen Reihe aus. Mit Hilfe von latch.await() wird gewartet, bis alle Tasks fertig sind.

Code


package com.stuelken.java.b4.parallel.c40.synchronizer;

import java.util.concurrent.CountDownLatch;

/**
 * @author t2m
 */
public class CountDownLatchExample {
	
	public static void main(String[] args) throws InterruptedException {
		new CountDownLatchExample().doCountDownLatch();
	}
	
	/**
	 * Use Case: Warten auf mehrere Vorbereitungen (z. B. Game-Assets,
	 * Spieler-Eingaben)
	 * @throws InterruptedException 
	 */
	public void doCountDownLatch() throws InterruptedException {

		CountDownLatch latch = new CountDownLatch(3);

		Runnable worker = () -> {
			System.out.println("Worker "+ Thread.currentThread().getName()+" gestartet");
			latch.countDown();
		};

		for (int i = 0; i < 10; i++) {
			new Thread(worker, "T "+i).start();
		}

		latch.await(); // blockiert bis alle Threads durch sind
		System.out.println("Alle Worker fertig");

	}
}
 

Ausgabe



// @formatter:off
/*
Worker T 0 gestartet
Worker T 3 gestartet
Worker T 2 gestartet
Worker T 1 gestartet
Alle Worker fertig
Worker T 5 gestartet
Worker T 6 gestartet
Worker T 7 gestartet
Worker T 8 gestartet
Worker T 4 gestartet
Worker T 9 gestartet
*/ 

Synchronizers | CyclicBarrier

C

Mit Hilfe des CyclicBarrier Synchronizers simulieren wir in diesem Beispiel ein Wettrennen. Alle Player-Runnables warten auf "Auf die Plätze", dann "Fertig" und "Los!".

In der Phase des Rennens wird mit Zufallszahlen Task für je 10 Meter im Rennen eine andere Laufzeit mitgegeben.

Code


package com.stuelken.java.b4.parallel.c40.synchronizer;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author t2m
 */
public class CyclingBarrierExample {

	public static void main(String[] args) {
		doCyclingBarrier();
	}

	/**
	 * Use Case: Alle Spieler müssen erst fertig sein, bevor die Runde fortschreitet
	 */
	public static void doCyclingBarrier() {

		int parties = 3;

		// Die Aktion, welche die CyclingBarrier ausführt.
		Runnable barrierAction_A = () -> {
			System.out.println("Auf die Plaetze!");
		};
		Runnable barrierAction_B = () -> {
			System.out.println("Fertig ... ");
		};
		Runnable barrierAction_C = () -> {
			System.out.println("Los!!!");
		};

		// Instanz erzeugten mit Anzahl der Akteure und der Aktion.
		CyclicBarrier barrierA = new CyclicBarrier(parties, barrierAction_A);
		CyclicBarrier barrierB = new CyclicBarrier(parties, barrierAction_B);
		CyclicBarrier barrierC = new CyclicBarrier(parties, barrierAction_C);

		// Jeder Spieler wird statt als Klasse kurzerhand als
		// Runnable einzig und allein mit einer Funktion
		// gestartet.

		Runnable player = () -> {
			String i = Thread.currentThread().getName();
			try {
				System.out.println("Spieler " + i + " wartet auf A");
				barrierA.await();
				System.out.println("Spieler " + i + " wartet auf B");
				barrierB.await();
				System.out.println("Spieler " + i + " wartet auf C");
				barrierC.await();
				Random r = new Random();
				for (int j = 0; j < 100; j = j + 10) {
					System.out.println("Spieler " + i + " rennt und erreicht " + j + "m");
					Thread.sleep(r.nextInt(1000) + 2000);
				}
				System.out.println("Spieler " + i + " kommt ins Ziel!");
			} catch (InterruptedException | BrokenBarrierException e) {
				e.printStackTrace();
			} // blockiert
			System.out.println("Spieler in Thread " + i + " jubelt!");
		};

		/*
		 * 3 Threads für je einen Player-Runnable.
		 */
		for (int i = 0; i < 3; i++) {
			Thread t = new Thread(player);
			t.setName("T" + i);
			t.start();
		}

		/*
		 * @todo: Berechne als Ergebnis des Programms, wer das Rennen am Ende gewonnen
		 * hat, indem nur Klassen/Interfaces aus java.concurrent statt Threads genutzt
		 * werden.
		 */

		/*
		 * @todo: Gebe aus, wer gerade im Verlauf des Rennens die Führung hat.
		 */

	}

} 

Ausgabe



// @formatter:off
/*
Spieler T1 wartet auf A
Spieler T2 wartet auf A
Spieler T0 wartet auf A
Auf die Plaetze!
Spieler T0 wartet auf B
Spieler T1 wartet auf B
Spieler T2 wartet auf B
Fertig ... 
Spieler T2 wartet auf C
Spieler T1 wartet auf C
Spieler T0 wartet auf C
Los!!!
Spieler T0 rennt und erreicht 0m
Spieler T2 rennt und erreicht 0m
Spieler T1 rennt und erreicht 0m
Spieler T0 rennt und erreicht 10m
Spieler T2 rennt und erreicht 10m
Spieler T1 rennt und erreicht 10m
Spieler T1 rennt und erreicht 20m
Spieler T0 rennt und erreicht 20m
Spieler T2 rennt und erreicht 20m
Spieler T1 rennt und erreicht 30m
Spieler T0 rennt und erreicht 30m
Spieler T2 rennt und erreicht 30m
Spieler T1 rennt und erreicht 40m
Spieler T0 rennt und erreicht 40m
Spieler T2 rennt und erreicht 40m
Spieler T1 rennt und erreicht 50m
Spieler T0 rennt und erreicht 50m
Spieler T2 rennt und erreicht 50m
Spieler T1 rennt und erreicht 60m
Spieler T0 rennt und erreicht 60m
Spieler T2 rennt und erreicht 60m
Spieler T0 rennt und erreicht 70m
Spieler T1 rennt und erreicht 70m
Spieler T2 rennt und erreicht 70m
Spieler T0 rennt und erreicht 80m
Spieler T1 rennt und erreicht 80m
Spieler T2 rennt und erreicht 80m
Spieler T1 rennt und erreicht 90m
Spieler T0 rennt und erreicht 90m
Spieler T2 rennt und erreicht 90m
Spieler T1 kommt ins Ziel!
Spieler in Thread T1 jubelt!
Spieler T0 kommt ins Ziel!
Spieler in Thread T0 jubelt!
Spieler T2 kommt ins Ziel!
Spieler in Thread T2 jubelt!

 */

Synchronizers | Phaser

Phaser

Ein Phaser-Synchronizer erstellt Phasen.

Code


package com.stuelken.java.b4.parallel.c40.synchronizer;

import java.util.concurrent.*;

public class PhaserHelper {

 public void doPhaser() throws InterruptedException, ExecutionException {
 	
 	int parties = 1;
 Phaser phaser = new Phaser(parties); // Hauptthread registriert

 Callable<String> phaseTask = () -> {
 phaser.register();
 for (int i = 1; i <= 4; i++) {
 System.out.println(Thread.currentThread().getName() + " Phase " + i + " gestartet");
 phaser.arriveAndAwaitAdvance(); // auf nächste Phase warten
 }
 return Thread.currentThread().getName() + " ist fertig.";
 };

 ExecutorService pool = Executors.newFixedThreadPool(3);
 Future<String> f1 = pool.submit(phaseTask);
 Future<String> f2 = pool.submit(phaseTask);
 Future<String> f3 = pool.submit(phaseTask);

 // Hauptthread nimmt ebenfalls an 4 Phasen teil:
 for (int i = 1; i <= 4; i++) {
 System.out.println("Main thread Phase " + i + " beendet");
 phaser.arriveAndAwaitAdvance();
 }

 // Ausgabe von Ergebnissen (damit main bis zum Ende wartet):
 System.out.println(f1.get());
 System.out.println(f2.get());
 System.out.println(f3.get());

 pool.shutdown();
 }

 public static void main(String[] args) throws InterruptedException, ExecutionException {
 new PhaserHelper().doPhaser();
 }
}


 

Ausgabe


// @formatter:off
/*
Main thread Phase 1 beendet
pool-1-thread-1 Phase 1 gestartet
pool-1-thread-2 Phase 1 gestartet
pool-1-thread-3 Phase 1 gestartet
pool-1-thread-3 Phase 2 gestartet
Main thread Phase 2 beendet
pool-1-thread-1 Phase 2 gestartet
pool-1-thread-2 Phase 2 gestartet
pool-1-thread-2 Phase 3 gestartet
Main thread Phase 3 beendet
pool-1-thread-3 Phase 3 gestartet
pool-1-thread-1 Phase 3 gestartet
pool-1-thread-1 Phase 4 gestartet
pool-1-thread-2 Phase 4 gestartet
pool-1-thread-3 Phase 4 gestartet
Main thread Phase 4 beendet
pool-1-thread-1 ist fertig.
pool-1-thread-2 ist fertig.
pool-1-thread-3 ist fertig.

*/

Exchanger

Synchronizers | Exchanger

Der Exchanger Synchronizer ermöglich es, dass ein Task in seinem Verlauf sich an einen Exchanger wendet, um mit exchange(..) einen Wert anzubieten und darauf zuwarten, dass ein anderer Thread auch einen Wert bietet, so dass die zwei Werte tauschen.

Dieses Verfahren ist an dem Punkt praktisch, dass die zwei Tasks unabhängig voneinander programmiert werden können und einzig und allein den Exchanger adressieren müssen.

Code


package com.stuelken.java.b4.parallel.c40.synchronizer;

import java.util.concurrent.Exchanger;

/**
 * @author t2m
 */
public class ExchangerExample {
	
	public static void main(String[] args) {
		new ExchangerExample().doExchanger();
	}

	/**
	 * 
	 */
	public void doExchanger() {
		Exchanger<String> exchanger = new Exchanger<>();

		new Thread(() -> {
			try {
				// Wartet auf einen anderen Thread.
				String response = exchanger.exchange("Ping from A");
				System.out.println(Thread.currentThread().getName()+" Erhielt: " + response);
			} catch (InterruptedException e) {
			}
		},"A").start();

		new Thread(() -> {
			try {
				// Wartet auf einen anderen Thread.
				String response = exchanger.exchange("Pong from B");
				System.out.println(Thread.currentThread().getName()+" Erhielt: " + response);
			} catch (InterruptedException e) {
			}
		},"B").start();

	}
}
 

Ausgabe



// B Erhielt: Ping from A
// A Erhielt: Pong from B 

Synchronizers | Semaphore

C

Das SemaphoreHelper Beispiele für die Semaphore zeigt, wie man den Zugriff auf jeweils 2 Tasks zur Zeit beschränken kann. Die Reihenfolge wird entweder unfair oder fair ermittelt: Bei fair stimmt die Reihenfolge mit der Registrierung überein.

Gesteuert wird der Ablauf über einen Executor in Verbindung mit einem CountDownLatch, damit zuerst der erste Teil mit unfair erfolgt und danach der zweite Teil mir fair.

Code


package com.stuelken.java.b4.parallel.c40.synchronizer;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * Semaphore dienen als Synchronizer für Rate Limiting, begrenzter
 * Ressourcenzugriff.
 * 
 * 
 * @author t2m
 *
 */
public class SemaphoreHelper {

	public static class MySemaphore {
	}

	public static void main(String[] args) {
		runExample();
	}

	/**
	 * 
	 */
	public static void runExample() {

		ExecutorService executor = Executors.newFixedThreadPool(10);
		
		// FALSCH!!!!
		// CountDownLatch latch = new CountDownLatch(10);
		// Jeder Latch wird nur 1x ausgeführt! Wir wollen
		// aber zwei Gruppen. 
		
		CountDownLatch latchUnfair = new CountDownLatch(10);
		CountDownLatch latchFair = new CountDownLatch(10);		

		/**
		 * Creates a Semaphore with the given number of permits and nonfair fairness
		 * setting. Parameters:permits the initial number of permits available.This
		 * value may be negative, in which case releasesmust occur before any acquires
		 * will be granted.
		 */
		Semaphore semaphoreNotFair = new Semaphore(2, false);
		Semaphore semaphoreFair = new Semaphore(2, true);

		/**
		 * 
		 */
		Runnable accessUnfair = () -> {

			try {
				/*
				 * {#1} Statt eines Monitor-Objekts wird ein Semaphore-Synchronizer verwendet.
				 * 
				 * Acquires a permit from this semaphore, blocking until one is available.
				 *
				 * <p>Acquires a permit, if one is available and returns immediately, reducing
				 * the number of available permits by one.
				 *
				 * <p>If no permit is available then the current thread becomes disabled for
				 * thread scheduling purposes and lies dormant until some other thread invokes
				 * the {@link #release} method for this semaphore and the current thread is next
				 * to be assigned a permit.
				 *
				 * <p>If the current thread is {@linkplain Thread#interrupt interrupted} while
				 * waiting for a permit then it will continue to wait, but the time at which the
				 * thread is assigned a permit may change compared to the time it would have
				 * received the permit had no interruption occurred. When the thread does return
				 * from this method its interrupt status will be set.
				 */
				System.out.println(Thread.currentThread().getName() + " wartet...");

				semaphoreNotFair.acquire(); // WICHTIG!

				System.out.println(Thread.currentThread().getName() + " darf rein");

				Thread.sleep(1000);

			} catch (InterruptedException e) {
			} finally {
				/*
				 * Releases a permit, returning it to the semaphore.
				 *
				 * <p>Releases a permit, increasing the number of available permits by one. If
				 * any threads are trying to acquire a permit, then one is selected and given
				 * the permit that was just released. That thread is (re)enabled for thread
				 * scheduling purposes.
				 *
				 * <p>There is no requirement that a thread that releases a permit must have
				 * acquired that permit by calling {@link #acquire}. Correct usage of a
				 * semaphore is established by programming convention in the application.
				 */
				System.out.println(Thread.currentThread().getName() + " released die Semaphore.");

				semaphoreNotFair.release(); // WICHTIG!
				
				// Wenn wir einen Latch verwenden, müssen wir dafür sorgen, dass
				// der Latch auch etwas zu zählen hat. Anderenfalls weiß
				// Latch nicht, wann alle Tasks abgearbeitet sind, und latch.await()
				// endet nicht. 
				latchUnfair.countDown(); // WICHTIG!				
				
			}
		};

		/**
		 * === Definition eines Runnables für "fair".
		 */
		Runnable accessFair = () -> {
			

			
			try {
				System.out.println(Thread.currentThread().getName() + " wartet...");
				semaphoreFair.acquire(); // WICHTIG!
				System.out.println(Thread.currentThread().getName() + " darf rein");
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			} finally {
				System.out.println(Thread.currentThread().getName() + " released die Semaphore.");
				semaphoreFair.release(); // WICHTIG! Nicht Fair/Unfair verwechseln!
				
				// Wenn wir einen Latch verwenden, müssen wir dafür sorgen, dass
				// der Latch auch etwas zu zählen hat. Anderenfalls weiß
				// Latch nicht, wann alle Tasks abgearbeitet sind, und latch.await()
				// endet nicht. 
				latchFair.countDown(); // WICHTIG!

			}
		};

		System.out.println("Unfair:");

		for (int i = 0; i < 10; i++) {
			new Thread(accessUnfair).start();
		}

		try {
			latchUnfair.await();

			System.out.println("\nUNFAIR-Fertig, jetzt FAIR...");
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		}

		System.out.println();
		System.out.println("Fair:");
		for (int i = 0; i < 10; i++) {
			new Thread(accessFair).start();
		}

		try {
			latchFair.await();
			System.out.println("\nFAIR-Fertig.");
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		}

		// Beenden.
		executor.shutdown();

	}

}
 

Ausgabe



// @formatter:off
/*
Unfair:
Thread-0 wartet...
Thread-0 darf rein
Thread-1 wartet...
Thread-1 darf rein
Thread-2 wartet...
Thread-3 wartet...
Thread-4 wartet...
Thread-5 wartet...
Thread-7 wartet...
Thread-6 wartet...
Thread-8 wartet...
Thread-9 wartet...
Thread-1 released die Semaphore.
Thread-0 released die Semaphore.
Thread-3 darf rein
Thread-2 darf rein
Thread-3 released die Semaphore.
Thread-2 released die Semaphore.
Thread-4 darf rein
Thread-5 darf rein
Thread-4 released die Semaphore.
Thread-7 darf rein
Thread-5 released die Semaphore.
Thread-6 darf rein
Thread-7 released die Semaphore.
Thread-8 darf rein
Thread-6 released die Semaphore.
Thread-9 darf rein
Thread-8 released die Semaphore.
Thread-9 released die Semaphore.

UNFAIR-Fertig, jetzt FAIR...

Fair:
Thread-11 wartet...
Thread-11 darf rein
Thread-10 wartet...
Thread-10 darf rein
Thread-12 wartet...
Thread-13 wartet...
Thread-14 wartet...
Thread-15 wartet...
Thread-16 wartet...
Thread-18 wartet...
Thread-17 wartet...
Thread-19 wartet...
Thread-11 released die Semaphore.
Thread-10 released die Semaphore.
Thread-12 darf rein
Thread-14 darf rein
Thread-12 released die Semaphore.
Thread-13 darf rein
Thread-14 released die Semaphore.
Thread-15 darf rein
Thread-13 released die Semaphore.
Thread-16 darf rein
Thread-15 released die Semaphore.
Thread-17 darf rein
Thread-17 released die Semaphore.
Thread-16 released die Semaphore.
Thread-18 darf rein
Thread-19 darf rein
Thread-18 released die Semaphore.
Thread-19 released die Semaphore.

FAIR-Fertig.

 */

Synchronizers | SemaphoreCompletableFutureDemo

C

Dieses Beispiel zeigt, wie man die zwei Varianten mit der fairen und der unfairen Semaphore getrennt nacheinander starten kann. Jede Semaphore lässt nur 2 Task auf einmal zu. CompleteableFuture ist der Ansatz, wie man in Java auch asynchron programmieren kann.

data

Code


package com.stuelken.java.b4.parallel.c40.synchronizer;

import java.util.concurrent.*;
import java.util.*;
import java.util.stream.*;

/**
 * 
 * @author t2m
 */
public class SemaphoreCompletableFutureDemo {

	public static void main(String[] args) {

		Semaphore semaphoreUnfair = new Semaphore(2, false);
		Semaphore semaphoreFair = new Semaphore(2, true);
		ExecutorService executor = Executors.newFixedThreadPool(10);

		// Erst unfair laufen lassen
		List<CompletableFuture<Void>> unfairTasks = IntStream.range(0, 10)
		 .mapToObj(
		 i -> CompletableFuture.runAsync(() -> task("Unfair-" + i, semaphoreUnfair), executor))
		 .collect(Collectors.toList());

		// Wenn alle unfair fertig → dann fair starten
		CompletableFuture
		 .allOf(unfairTasks.toArray(new CompletableFuture[0]))
		 .thenRun(() -> {
			 System.out.println("\nAlle Unfair-Tasks fertig. Starte Fair-Phase...\n");
			 List<CompletableFuture<Void>> fairTasks = IntStream.range(0, 10)
			 .mapToObj(
			 i -> CompletableFuture.runAsync(() -> task("Fair-" + i, semaphoreFair), executor))
			 .collect(Collectors.toList());

			 CompletableFuture
			 .allOf(fairTasks.toArray(new CompletableFuture[0]))
			 .thenRun(() -> {
				 System.out.println("\nAlle Fair-Tasks abgeschlossen.");
				 executor.shutdown();
			 });
		 });
	}

	static void task(String name, Semaphore semaphore) {
		try {
			System.out.println(name + " wartet...");
			semaphore.acquire();
			System.out.println(name + " hat Zugriff");
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		} finally {
			semaphore.release();
			System.out.println(name + " gibt Zugriff frei");
		}
	}
}

Ausgabe




// @formatter:off
/*
Unfair-0 wartet...
Unfair-9 wartet...
Unfair-8 wartet...
Unfair-7 wartet...
Unfair-5 wartet...
Unfair-6 wartet...
Unfair-4 wartet...
Unfair-3 wartet...
Unfair-2 wartet...
Unfair-1 wartet...
Unfair-9 hat Zugriff
Unfair-0 hat Zugriff
Unfair-4 hat Zugriff
Unfair-9 gibt Zugriff frei
Unfair-0 gibt Zugriff frei
Unfair-3 hat Zugriff
Unfair-4 gibt Zugriff frei
Unfair-5 hat Zugriff
Unfair-3 gibt Zugriff frei
Unfair-7 hat Zugriff
Unfair-7 gibt Zugriff frei
Unfair-5 gibt Zugriff frei
Unfair-6 hat Zugriff
Unfair-8 hat Zugriff
Unfair-2 hat Zugriff
Unfair-6 gibt Zugriff frei
Unfair-8 gibt Zugriff frei
Unfair-1 hat Zugriff
Unfair-2 gibt Zugriff frei
Unfair-1 gibt Zugriff frei

Alle Unfair-Tasks fertig. Starte Fair-Phase...

Fair-0 wartet...
Fair-0 hat Zugriff
Fair-2 wartet...
Fair-2 hat Zugriff
Fair-1 wartet...
Fair-4 wartet...
Fair-3 wartet...
Fair-7 wartet...
Fair-6 wartet...
Fair-5 wartet...
Fair-8 wartet...
Fair-9 wartet...
Fair-0 gibt Zugriff frei
Fair-1 hat Zugriff
Fair-4 hat Zugriff
Fair-2 gibt Zugriff frei
Fair-3 hat Zugriff
Fair-7 hat Zugriff
Fair-1 gibt Zugriff frei
Fair-4 gibt Zugriff frei
Fair-7 gibt Zugriff frei
Fair-5 hat Zugriff
Fair-6 hat Zugriff
Fair-3 gibt Zugriff frei
Fair-5 gibt Zugriff frei
Fair-8 hat Zugriff
Fair-6 gibt Zugriff frei
Fair-9 hat Zugriff
Fair-8 gibt Zugriff frei
Fair-9 gibt Zugriff frei

Alle Fair-Tasks abgeschlossen.


 */
UI ORGANIZED.

UIO3 Es ist einfacher als Du denkst.

Stelle noch heute Deine Anfrage.

uio--WebPageFooter-Module