← blog.defg.xyz

Shared mutable, Isolated mutable and Immutable state in Concurrency explained by a Kitchen analogy

July 3, 2013 · Concurrency

After reading a book on concurrency and going through some examples, I found myself thinking about explaining different types of concurrency designs using an example of a few roommates cooking dinner together in a shared kitchen.

In this analogy we'll make the following associations:

A number of roommates cooking together — number of threads performing a task
The task — preparing and eating a meal
The resource — a shared pot of soup

In case of computers, the number of threads is estimated based on the number of available CPUs * number of cores, taking into account the blocking coefficient of the threads. The general rule is to increase the number of threads beyond CPU*Cores if the application does a lot of I/O in threads, e.g. reading files, making a blocking DB call or web request. Or conversely, keep the number of threads close to CPU*Cores if the application is mostly doing heavy computation. That's a separate topic though — for our example, let's say there are three roommates sharing the kitchen, enough for concurrency to get interesting.

Shared mutable state

So here we go. In this case, three roommates share a single pot of soup on the stove, with one shared spoon, and no individual bowls yet — everyone has to take turns tasting and stirring directly from the pot. Imagine three hungry roommates queuing up just to get a taste. That's the worst-case scenario. Only one can access the pot at a time while the others wait — that's the concurrency problem right there.

And if you skip the queue and let everyone reach in with their own spoon at once without coordinating? Someone adds salt without knowing someone else already did, someone else's spoon knocks the pot off the stove — dinner is ruined and the kitchen's a mess. That's exactly what happens when multiple threads mutate shared state without synchronization: unpredictable side effects that are miserable to debug.

So yes — this is bad design and should be avoided as much as possible. Try not to share mutable state directly!

Isolated mutable state

This time, the roommates still start from one shared pot, but now everyone gets their own bowl. What's improved? First, it's a lot more civilized. Second, from a resource-sharing perspective, there's still one pot, but before anyone can actually eat, each bowl gets filled first — dividing the resource before the real work (eating, seasoning to taste, adding your own toppings) begins. This reduces waiting and increases time spent actually doing the task.

Everyone can then take their own bowl and finish it at their own pace — some eat fast, some slow, depending on how hungry they are or how much they're doing at once. In programming, this model shows up as thread pools or executor services: one dispatcher thread hands out portions of work, and multiple worker threads process their own chunk independently. The only contention is at hand-off time — once each worker has its own copy of the work, there's no more waiting.

Immutable state

This is the "Nirvana" scenario. Here, everyone gets a fully separate, already-plated portion from the start — like grabbing a sealed meal-prep container. There's zero dependency between roommates. Everyone can eat at their own pace, reheat, season, or even completely ignore their portion without affecting anyone else's.

In the computing world, this is the best possible situation for threads: the shared mutable state is removed entirely, and each thread works with its own copy of the data. No contention, no waiting, no risk of one thread's changes silently breaking another's work. Best possible scenario!

That said, cooking — like most things worth doing — is still better shared. The trick isn't to avoid cooking together, it's making sure nobody's reaching into the same pot with the same spoon at the same time.