Tre paradigmi di uso comune sono gli attori (ad esempio Akka), la memoria transazionale del software (ad esempio Clojure) o il tradizionale blocco manuale delle serrature. Hanno tutti le loro sfide.
La tradizionale programmazione basata su lock comporta il rilevamento dei luoghi che necessitano di protezione dalla corruzione tramite accessi concorrenti, la protezione tramite blocchi e la speranza che la soluzione sia corretta, senza deadlock ed efficiente. (Venkat Subramaniam lo chiama "sincronizzare e soffrire"). Ci sono molti problemi con questo approccio: molte lingue non ti aiutano praticamente a garantire la correttezza. Lo sviluppo non è scalabile perché la sicurezza dei thread non è preservata in base alla composizione (ogni volta che si modifica qualcosa sul proprio codice, è necessario riprovare che la soluzione è corretta). Sebbene questo modello sia alla base di tutti gli altri modelli, è in effetti la programmazione dell'assemblatore della concorrenza e altrettanto spiacevole con cui lavorare.
Attori che già conosci. I concetti fondamentali qui sono i messaggi asincroni e la responsabilità esclusiva di un attore per il suo stato mutevole. La parola d'ordine è mutabilità isolata . Uno dei problemi con questo è che può diventare molto inefficiente se una delle risorse nascoste dietro un attore è un collo di bottiglia. Ed è ancora possibile creare deadlock quando si utilizzano gli attori in modo improprio.
La memoria transazionale del software è meglio vista come immutabilità condivisa . La solita spiegazione è che ogni thread fa solo ciò che vuole e un monitor annulla l'intera sequenza di un thread se rileva che un conflitto si è effettivamente verificato. Una bella metafora è l'aggiornamento di un servizio web senza tempi di inattività: è sufficiente configurare un secondo server identico, aggiornarlo e, se funziona, lanciare un interruttore per reindirizzare tutto il traffico verso il nuovo indirizzo e chiudere quello vecchio. Se si è verificato qualcosa di imprevisto (ad esempio, i requisiti sono cambiati prima dell'aggiornamento), basta semplicemente scartare il nuovo server e ricominciare da capo.
Lo svantaggio con STM è che tutte le copie necessarie per mantenere l'immutabilità possono diventare costose e la programmazione può essere davvero difficile da capire. STM è fondamentalmente una programmazione senza blocco con una vendetta, e la programmazione lock-free è difficile per molte menti come è. Spesso richiede di trovare nuovi algoritmi per i problemi che si pensava fossero già stati risolti molto tempo fa. E ancora, è efficiente solo fino a quando i conflitti e i rollback sono relativamente rari.
Quale modello scegliere dipende da molti fattori; la mia impressione personale è che il supporto degli strumenti è in realtà più importante del paradigma sottostante. È molto più facile programmare con un paradigma non familiare con un buon supporto linguistico piuttosto che con un linguaggio familiare con quasi nessuno.