synchronized is een sleutelwoord dat het mogelijk maakt om thread-veilige toegang tot kritieke gedeelten van de code uit te voeren. Het kan worden gebruikt voor een methode (bijv. public synchronized void foo()) of voor een codeblok (synchronized(obj) { ... }). Wanneer een thread de synchronized-blok binnenkomt, verwerft hij de monitor (lock) van het object. Terwijl de monitor bezet is, kunnen andere threads niet binnenkomen in een andere synchronized-blok die hetzelfde object als monitor gebruikt.
Kenmerken:
this, op een statisch object (bijv. op de klasse), of op een willekeurig object.public class Counter { private int count; private final Object lock = new Object(); // privé object public void increment() { synchronized(lock) { count++; } } }
Waarom is het beter om een privé lock te gebruiken? Omdat als je synchroniseert op een publiek object (bijv. op this of op een publiek string), externe code deze monitor kan veroveren, wat leidt tot deadlocks of incorrecte werking.
Vraag: Wat gebeurt er als je synchroniseert op een object van het type String dat een vast waarde bevat?
Antwoord: Strings in Java zijn geïnternd (dezelfde objecten voor identieke literalen). Als je synchroniseert op een string zoals synchronized("lock"), kun je per ongeluk in conflict komen met andere code die synchroniseert op dezelfde literale, wat leidt tot onverwachte blokkades tussen totaal verschillende delen van het programma.
synchronized("LOCK") { ... }
Verhaal
In een multi-threaded handelsysteem werden publieke objecten gebruikt voor synchronisatie, waardoor externe code de lock kon veroveren, wat leidde tot tijdelijke deadlocks tussen threads van verschillende modules en stilstand op de beurs.
Verhaal
Een jonge ontwikkelaar synchroniseerde de toegang tot een collectie op een stringliteral. Een ander deel van de code synchroniseerde ook op een string met dezelfde waarde. Deze threads stonden in de rij achter elkaar, wat leidde tot een aanzienlijke vertraging van de bedrijfslogica.
Verhaal
Er werd elke keer een nieuw object gekozen voor synchronisatie:
synchronized(new Object()) { ... }. Als gevolg hiervan werkte de synchronisatie helemaal niet, en hadden verschillende threads gelijktijdig toegang tot de gegevens. Dit werd pas ontdekt tijdens belastingtesten.