Is it OK to use a string as a lock object?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Java, synchronizing on a String is legal, but it is rarely a good design choice. The issue is not whether the syntax works. The issue is that strings are easy to share accidentally, which can make unrelated code block on the same monitor without anyone intending that behavior.
Why String Locks Become Shared Accidentally
Java interns string literals. Equal literals often refer to the same object, which means two classes can end up synchronizing on the exact same monitor even if they were written independently.
That shared identity is what makes string-based locking risky. The lock object may appear local in the source file while actually being globally shared in practice.
A Hidden Contention Example
This code compiles and looks harmless:
ServiceA and ServiceB can now block each other because the string literal refers to the same interned object. That kind of coupling is difficult to discover during code review and frustrating to diagnose in production.
Use a Dedicated Private Lock Object Instead
The safest default is to create a private final object whose only purpose is synchronization.
This approach gives the lock a single owner and prevents accidental interaction with external code.
Keep the Lock Encapsulated
Even a non-string lock becomes dangerous if it is exposed outside the class. Good locking discipline means:
- make the lock field
private - make it
final - never return it from a getter
- document what state it protects
Lock design is part of encapsulation. If other code can synchronize on your lock, it can stall your internal implementation.
Use ReentrantLock When You Need More Control
Sometimes synchronized is not expressive enough. If you need timeouts, interruption support, or explicit lock management, prefer ReentrantLock over inventing a lock strategy based on strings.
This is clearer, more flexible, and easier to reason about than synchronizing on a value-like object.
Avoid intern() as a Lock Registry
Some code uses intern() deliberately to create shared lock keys from strings. While that can work in narrow cases, it creates global coordination through the string pool and makes concurrency behavior much harder to predict.
If you truly need keyed locking inside one JVM, a dedicated lock registry is usually a better design.
This still needs lifecycle thought, but at least the sharing is explicit and under your control.
Common Pitfalls
One pitfall is assuming a string constant is private enough to be safe. With interning, its identity may already be shared more broadly than expected.
Another is choosing a string lock because the string was already available. Convenience is a poor reason to define a synchronization boundary.
Developers also forget that sometimes a lock is the wrong abstraction entirely. A concurrent collection, atomic type, or message-passing design may be simpler and safer.
Summary
- Using a
Stringas a Java lock object is usually a bad practice. - String interning can create accidental shared monitors across unrelated code.
- Prefer a private final lock object with one owner and one purpose.
- Use
ReentrantLockwhen you need advanced locking behavior. - If you need key-based locking, build an explicit registry instead of relying on string interning.

