final int y; // <- Y not // not thread safe! public FinalConcurrent() { x = 3; y = 4; } } class ConcurentUsage { FinalConcurrent f; @Thread1 void writer() { f = new FinalConcurrent(); } @Thread2 void reader() { if(f != null) { int i = f.x; // <- Das JMM garantiert den Wert 3! int y = f.y; // <- `y` kann hier 0 oder 4 sein. } } } flush final refresh Synchronisierung - final
void write() { number = 999999999999L; flag = true; } @Thread2 void read() { if(flag) { System.out.println(number); } } } flush volatile gilt nur für primitive Werte und Objektreferenzen. Nicht für die Objekte selbst! refresh Synchronisierung - volatile
String lastname; public final LocalDate birthDate; public Person (String firstname, String lastname, LocalDate birthDate) { … } public Person birthday() { return new Person( firstname, lastname, birthDate.plusYears(1) ); } } Objekte müssen immutable sein. “Verändernde” Methoden liefern Kopien. Funktioniert gut in Verbindung mit volatile. Patterns - Immutable Objects
person; } public void setBirthday(Person person) { this.person = person.birthday(); } public Person get() { return this.person; } `volatile` liefert die threadsicherheit für die Referenz. `Person` liefert die threadsicherheit durch “Immutability”. Patterns - Immutable Objects
yearOlderFuturePerson.get(); ScheduledExecutorService executorService = Executors.newScheduledThreadPool(128); CompletableFuture<Person> someFuturePerson = CompletableFuture.supplyAsync( () -> { try { Thread.sleep(400); return new Person("Hans", "Dampf", LocalDate.of(1983, 6, 14)); } catch (InterruptedException e) { ... } }, executorService); Läuft in einem Thread Wird erst später, bei einem Ergebnis ausgeführt Erst hier wird geblockt Patterns - Futures
new CopyOnWriteArrayList<>(); ReentrantReadWriteLock reentrantLock = new ... readWriteLock.readLock(); readWriteLock.writeLock(); Semaphore semaphore = new Semaphore(3); semaphore.acquire(); semaphore.acquire(); semaphore.acquire(); semaphore.acquire(); // blocks! ReentrantLock reentrantLock = new ... reentrantLock.lock(); // Make some synchronized stuff reentrantLock.unlock(); new UnmodifiableList(someMutableList); Patterns - Viele kleine Helferlein
class Employee(val firstName: FirstName, val lastName: LastName) val max = Employee(FirstName("Max"), LastName("Mustermann")) val updatedEmployee = max.copy(lastName = LastName("Musterfrau")) Data classes val deferred: Deferred<Int> = GlobalScope.async { delay(1000) println("Async") 13 + 29 } val result: Int = runBlocking { deferred.await() } Coroutines val list: List<String> = listOf("blue", "green", "red") val newList: List<String> = list + "yellow" Immutable Collection
verhindern. • Identifiziere gemeinsam genutzte Objekte. • Schütze diese Objekte, und nur diese, mit Synchronisierung. • Bevor du einen eigenen Thread startest, prüfe, ob auch ein Threadpool hilft. Grundsätze