It’s just for API convenience. If you use a raw ReentrantLock, you need to pass around the lock and the thing it locks together, and remember which lock goes with which data. By using Lockable, the lock and the thing it locks is wrapped in a struct so you can’t forget that the data is protected by a lock, or access the data without the lock, or accidentally mix up multiple locks.
So, it’s API protection against mistakes.
That would be the expected thing, and what the source-code comments suggest.
It is not what julia is actually doing julia/base/lock.jl at bcda9827f52772efc3122230fc47220bdfed8756 · JuliaLang/julia · GitHub
The source-code comment claims that we spin for the lock, but we don’t. Instead we repeatedly call Base.yield(), which basically tells the julia scheduler to find other work. If the julia scheduler found other work, then we pay the full cost of context switching; if it didn’t, then it will try to take the lock again (a spin with extra steps).
My personal thought is that this current procedure sucks. We should spin for some time (aka try again after some pause instructions). Then we should not Base.yield(), and instead immediately park on the lock. We tell the scheduler that we’re blocked, but refuse to tell it by what we’re blocked.