BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ Concurrency

Concurrency

Distributed locks and job locking (ShedLock)

When several copies of an application run at once, an ordinary synchronized or ReentrantLock only protects one copy.

Learn these first

At a glance

Mental model

One meeting-room key kept at the front desk instead of a sticky note on each door.

What happens, in order
  1. 1ShedLock wraps scheduled methods: @SchedulerLock(name = "nightlyReport", lockAtMostFor = "10m") makes sure that across all instances only the one that grabs the lock row or Redis key runs it
  2. 2Redisson (RLock), Spring Integration (LockRegistry) and Curator (ZooKeeper) offer a lock object: lock.tryLock(...), work, unlock() in a finally block
  3. 3Every distributed lock has an expiry (lease time) so that a crashed holder does not block everyone forever
  4. 4Database advisory locks and SELECT ..FOR UPDATE are simpler options when the shared database is the resource being protected.
Remember
Watch out
Forgetting unlock() in a finally blockLease shorter than the job durationRelying on a lock for correctness without idempotent workIn-JVM locks for multi-instance deployments
Example (highlighted lines explain it)
RLock lock = redisson.getLock("invoice-run");if (lock.tryLock(0, 30, TimeUnit.MINUTES)) {    try {        invoiceService.runMonthly();    } finally {        lock.unlock();    }}
  1. line 1 uses RLock, the core of Distributed locks and job locking (ShedLock)
Read the full explanation (about 2 min)

When several copies of an application run at once, an ordinary synchronized or ReentrantLock only protects one copy. A distributed lock uses a shared store (database, Redis, ZooKeeper) so that only one instance at a time runs a job or touches a resource.

A mental model

One meeting-room key kept at the front desk instead of a sticky note on each door. Everybody in the building has to ask the desk, so two teams cannot both believe the room is theirs.

How it works

ShedLock wraps scheduled methods: @SchedulerLock(name = "nightlyReport", lockAtMostFor = "10m") makes sure that across all instances only the one that grabs the lock row or Redis key runs it.

Redisson (RLock), Spring Integration (LockRegistry) and Curator (ZooKeeper) offer a lock object: lock.tryLock(...), work, unlock() in a finally block.

Every distributed lock has an expiry (lease time) so that a crashed holder does not block everyone forever.

Database advisory locks and SELECT ... FOR UPDATE are simpler options when the shared database is the resource being protected.

Going deeper

A lease can expire while the holder is still working (a long GC pause or slow call). Two instances then both believe they hold the lock. For correctness, use fencing tokens or make the work idempotent, and treat the lock as an efficiency measure, not a guarantee.

lockAtMostFor must be longer than the job ever takes and lockAtLeastFor stops a fast job from running again on a node with a slightly different clock.

Clock differences between nodes matter for time-based leases; use the database or Redis server time where possible.

Under the hood

Redis-based locks use SET key value NX PX ttl (set if not exists with expiry) and release with a Lua script that checks the stored owner token, so one holder cannot delete another lock. JDBC providers insert or update a row guarded by a unique key with a lock-until timestamp.

Common mistakes

  • Forgetting unlock() in a finally block.
  • Lease shorter than the job duration.
  • Relying on a lock for correctness without idempotent work.
  • In-JVM locks for multi-instance deployments.

How Unravel recognises it

When you paste code, Unravel looks for these signs of distributed locks and job locking (shedlock). Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Distributed locks and job locking (ShedLock)?

When several copies of an application run at once, an ordinary synchronized or ReentrantLock only protects one copy. A distributed lock uses a shared store (database, Redis, ZooKeeper) so that only one instance at a time runs a job or touches a resource.

What are the most common mistakes with Distributed locks and job locking (ShedLock)?

Forgetting unlock() in a finally block. Lease shorter than the job duration. Relying on a lock for correctness without idempotent work. In-JVM locks for multi-instance deployments.

How can I see Distributed locks and job locking (ShedLock) in real code?

Paste your own Java into Unravel and it will point out where distributed locks and job locking (shedlock) appears, explain how it works at the detail level you choose, and draw the flow of the code around it.