ProgrammatieJava middle/backend ontwikkelaar

Wat weet u over het werken met threads in Java en hoe de threadveiligheid te organiseren?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

In Java wordt het werken met threads geïmplementeerd via de klassen Thread, Runnable en uit het pakket java.util.concurrent. Voor het organiseren van threadveiligheid worden verschillende synchronisatiemechanismen gebruikt:

  • Gelsynchroniseerde blokken/ methoden (synchronized) stellen meerdere threads in staat om toegang te krijgen tot gedeelde gegevens zonder racecondities.
  • volatile garandeert de zichtbaarheid van wijzigingen in een variabele tussen threads.
  • Klasse uit java.util.concurrent (bijv. ReentrantLock, Semaphore, AtomicInteger, ConcurrentHashMap) bieden flexibeler manieren van synchronisatie.

Voorbeeld van synchronisatie:

public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }

Voorbeeld met gebruik van atomische klassen:

import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }

Vraag met een valstrik.

Garandeert het sleutelwoord volatile threadveiligheid bij het verhogen van een int-teller?

Antwoord: Nee. volatile biedt alleen zichtbaarheid van de waarde tussen threads, maar niet de atomiciteit van bewerkingen. Verhogen is geen atomische bewerking (count++ bestaat uit lezen, verhogen en schrijven), daarom kunnen gegevens verloren gaan. Voor threadveilige verhogingen zijn synchronisatie of klassen zoals AtomicInteger nodig.

volatile int count = 0; // count++ is niet threadveilig!

Voorbeelden van echte fouten door onbekendheid met de nuances van het onderwerp.


Verhaal

In een online winkel werd de bonusrekening bijgewerkt via een volatile-teller. Onder belasting bestelden duizenden gebruikers producten, en een deel van de bonussen ging verloren vanwege racecondities op count++.


Verhaal

Een medewerker gebruikte een gewone ArrayList als een gedeelde buffer tussen een producent en een consument in een multithread-applicatie, wat resulteerde in ConcurrentModificationException. De oplossing was het gebruik van synchronized-blokken of vervanging door CopyOnWriteArrayList.


Verhaal

Bij de verwerking van betalingen voerde een ontwikkelaar de operatie "controleer en neem het bedrag af" uit via twee niet-verbonden methoden. Onder hoge belasting leidde dit tot dubbele afschrijvingen, totdat atomische transacties en vergrendelingen werden geïmplementeerd.