Voorstel voor inhoud behandeling threads Concept 0.2, 24 januari 2014 Sjaak Smetsers en Lex Bijlsma Publiek In het onderstaande zijn we uitgegaan van een publiek dat bestaat uit postpropedeusebachelorstudenten informatica zonder bijzondere specialisatie in parallellisme. Te behandelen onderwerpen 1. Motivatie Threads zijn nodig om te bewerkstelligen dat de gebruikersinterface van een applicatie blijft reageren ook als achter de schermen intensief rekenwerk plaatsvindt. Dit weegt extra zwaar bij clientservertoepassingen met een groot aantal clients, zoals in webapplicaties gebruikelijk is. Daarnaast maken threads bij het simuleren van processen in de werkelijkheid met inherent parallellisme de programmacode veel eenvoudiger. 2. Locking Men spreekt van een raceconditie als het effect van de code afhangt van de relatieve snelheid waarmee verschillende threads vorderingen maken. Racecondities treden op zodra threads 'onbeschermd' gebruik maken van gemeenschappelijke variabelen waarbij tenminste één thread de waarde van deze variabele(n) wijzigt. Om racecondities te voorkomen, is het nodig de toegang tot deze gemeenschappelijke variabelen te regelen via gesynchroniseerde secties. Als tussen de toestand van verschillende variabelen (zogenaamde verbonden variabelen) een verband gehandhaafd moet worden doordat ze gezamenlijk in een globale invariant voorkomen, moeten deze variabelen door hetzelfde lock worden beschermd. 3. Deadlock en starvation Als gevolg van bovenstaande maatregelen kan het voorkomen dat het programma geen voortgang meer maakt omdat de verschillende threads op elkaar wachten (deadlock), en ook dat een bepaalde thread geen voortgang meer maakt doordat steeds andere aan de beurt zijn (starvation). Deze verschijnselen kunnen veelal worden voorkomen door geen externe methoden aan te roepen binnen een synchronized sectie of door het verwerven van locks aan een vaste volgorde te binden. 4. Wait en notify Het komt vaak voor dat een thread pas verder kan gaan met de uitvoering van een gesynchroniseerde sectie als aan een extern bepaalde conditie is voldaan. In dat geval kan de executie tijdelijk worden stopgezet (en de sectie worden vrijgegeven) door middel van de opdracht wait(), een toestand die kan worden beëindigd als door een andere thread notifyAll() wordt aangeroepen. 5. Het producent/consument-probleem In een producent/consument samenwerking genereert de producent data om die vervolgens op te slaan in een gedeeld object dat door de consument gebruikt wordt om de genereerde data uit te lezen en vervolgens verder te verwerken. De essentie van deze vorm van samenwerken is dat het identificeren van werk en de daadwerkelijke uitvoering hiervan gescheiden zijn. Het gedeelte object, wat in feite zorgdraagt voor het opvangen van het verschil in verwerkingsmoment en –tijd, heet een buffer. Het is evident dat de gemeenschappelijke toegang tot deze buffer synchronisatie vereist. 6. Gesynchroniseerde objecten Een klasse is thread-safe als de veranderlijke attributen privé zijn en alleen kunnen worden geaccesseerd via gesynchroniseerde methoden. In geval van een thread-safe klasse hoeven cliënten van de klasse geen moeite te doen om racecondities te vermijden, tenzij er sprake is van meerdere variabelen uit verschillende thread-safe klassen die onderling door een invariant verbonden zijn. De Java-bibliotheken kennen vele thread-safe klassen, die kunnen worden gecreëerd door factory methods in java.util.Collections uit de standaard sequentiële collecties (bijvoorbeeld Set s = Collections.synchronizedSet(new HashSet());), of als instanties van de zogenaamde concurrent collections uit het java.util.concurrent package (bijvoorbeeld BlockingQueue bq = new ArrayBlockingQueue(10);). Er is een verschil tussen synchronized en concurrent collections: laatstgenoemde hebben een betere performance. Te vermijden onderwerpen We willen niet beweren dat de onderstaande onderwerpen niet belangrijk zijn, maar wel dat ze op het bedoelde expertiseniveau niet binnen redelijke tijd adequaat te behandelen zijn. – Details van de JVM – Zichtbaarheid en het effect van volatile – De deprecated methode stop() – Publicatie van onvolledig geïnitialiseerde objecten – Thread confinement en ThreadLocal – Latches – …