N threads all race to call get_instance() on a lazily-initialized singleton at (roughly) the same time. Print how many times the singleton was actually constructed.
Why this is gradable. Concurrent code can legitimately produce different interleavings on every run, so this practice bank only includes problems whose correctness reduces to one deterministic final value or invariant — never a specific thread ordering. If your solution is correct, it will print the exact same output on every run, no matter how the scheduler interleaves your threads. A correct singleton is constructed exactly once, no matter how many threads race for it or how the scheduler interleaves them.
Example
Input: 20
Output: 1
Why the naive version is wrong
if instance is None: instance = Instance() has a classic race: two threads can both pass the is None check before either finishes constructing, and both end up building (and one overwriting) an instance — so the "construction count" ends up bigger than 1, non-deterministically.
Approach: double-checked locking
Check if the instance already exists (fast path, no lock — cheap for the common case where it's already built).
If not, acquire a lock.
Check again inside the lock — another thread may have finished building it while you were waiting for the lock.
Only if it's still missing, construct it.
This gives you both correctness (only one thread ever constructs it) and performance (most calls, after the first, never touch the lock).
Walkthrough
python
1@classmethod
2def get_instance(cls):
3 if cls._instance is None:
4 with cls._lock:
5 if cls._instance is None:
6 cls._instance = cls()
7 cls._init_count += 1
8 return cls._instance
Step 1 / 5
Thread A's fast-path check (outside the lock): instance is None, so it heads toward the lock.
Input format
Line 1: N, the number of racing threads
Print the number of times the singleton was constructed.
Not solved yet
Ctrl+Enter
Editor
import threading
n = int(input())
classSingleton:
_instance = None
_lock = threading.Lock()
_init_count = 0 @classmethoddefget_instance(cls):
# TODO: double-checked locking — check outside the lock, then again inside it,# before constructing. Only ever increment _init_count once.pass
threads = [threading.Thread(target=Singleton.get_instance) for _ inrange(n)]
for t in threads:
t.start()
for t in threads:
t.join()
print(Singleton._init_count)
Input (stdin)
Output
Run your code to see output here.
Isolated sandbox · not executed on your devicePowered by Judge0 CE (free, self-hosted). Runs in an isolated sandbox — not on your device.
Editor
import threading
n = int(input())
classSingleton:
_instance = None
_lock = threading.Lock()
_init_count = 0 @classmethoddefget_instance(cls):
# TODO: double-checked locking — check outside the lock, then again inside it,# before constructing. Only ever increment _init_count once.pass
threads = [threading.Thread(target=Singleton.get_instance) for _ inrange(n)]
for t in threads:
t.start()
for t in threads:
t.join()
print(Singleton._init_count)
Input (stdin)
Output
Run your code to see output here.
Isolated sandbox · not executed on your devicePowered by Judge0 CE (free, self-hosted). Runs in an isolated sandbox — not on your device.