Master Clojure concurrency
You've heard that Clojure is great for concurrency. But what tools does Clojure give you? And how should you use those tools? There are a lot of tools available, and each has its strengths and weaknesses. It can be difficult to learn how to choose between them. But once you do, you'll be firing up threads left and right to get work done in parallel.
These lessons are meant to each answer a specific question and help you build the skills you need to address a wide variety of concurrency problems.
Want this course?
Love it or leave it guarantee
If you don't learn as much from this course as you thought, just ask for a refund within 30 days and I'll give you your money back.
File downloads for this course are below. Jump down
Sometimes you have a shared bit of code that you only want run once, even if you want to share the result of the code. How is that like a coffee pot? Well, we'll see!
Sometimes we want to use another Thread to do some work, but we need the result of that work back in the main Thread. We can have the worker thread promise to put the value in a Promise. We can deref the Promise and get it out or block.
Sometimes you want to perform a calculation in another Thread and capture it in something like a Promise in one go. That's what Future is for.
deref is an important function because it is used so much in Clojure. It's used to get the current value out of the reference types in Clojure, including Atoms, Refs, Vars, Futures, Promises, and Delays. There are some things you need to know about it.
Keeping state consistent with Atoms
If we share mutable state between threads, the values can become inconsistent. Clojure uses Atoms to ensure that a mutable value is always consistent, even when written to by multiple threads.
Sharing state among many threads: Atoms
How do you use atoms to help many threads share state? The video is 10 minutes long.
Whenever you need to keep two or more values in a consistent relationship, Refs are available. They give you transactional properties across multiple Refs. We look at the example of calculating an average and keeping a Farenheit value consistent with a Celsius reading.
You'll typically use Vars in three use cases. 1) Dynamic development 2) Dynamic scope 3) testing. Most of the time, you won't even know you're using them because they're baked into the language.
Agents are another reference type. Each one has a queue of work to be run on it, and those bits of work get run in a thread pool. They're great because each Agent is a unit of parallelization. Three Agents mean three things can run at the same time.
Locking is a low-level mechanism for making sure only one Thread runs some code at the same time. It's like a lock on your bathroom. It keeps others out so you can do what you need to do in peace.
Core Async is a library for concurrency brought to us by the core Clojure team. I love it because it's a game changer for complex concurrent tasks. It's very versatile and can be used to implement many common patterns.
The basic unit of parallelization in the JVM is the Thread. Java provides a mechanism for creating and starting native Threads. We go over how to use them.
Java provides a library called ExecutorService. It's a thread pool fed by a queue. You send it tasks (functions) and you get back Futures with your answers.
Fork/Join is a library that comes with Java for doing highly parallel computations. It lets you recursively break up work, do the work, and put the pieces back together.