1212/**
1313 * Distributed lock implementation based on the File system.
1414 * Usage:
15+ *
1516 * <pre>
1617 * {@code
1718 * Lock lock = Watcher.getInstance().acquire();
@@ -32,11 +33,13 @@ public class DistributedLock implements Lock {
3233 private final String id ;
3334 private final Watcher watcher ;
3435 private volatile Thread owner ;
36+ private volatile int holdCount = 0 ;
3537
3638 private static final Logger logger = Logger .getLogger (DistributedLock .class .getName ());
3739
3840 /**
39- * Constructor to create a new DistributedLock instance with a random UUID as the lock ID.
41+ * Constructor to create a new DistributedLock instance with a random UUID as
42+ * the lock ID.
4043 */
4144 public DistributedLock () {
4245 this .id = UUID .randomUUID ().toString ();
@@ -46,7 +49,8 @@ public DistributedLock() {
4649 }
4750
4851 /**
49- * Constructor to create a new DistributedLock instance with a specified lock ID.
52+ * Constructor to create a new DistributedLock instance with a specified lock
53+ * ID.
5054 *
5155 * @param idb Byte array representing the lock ID.
5256 */
@@ -62,18 +66,20 @@ public DistributedLock(String lockId) {
6266 }
6367
6468 /**
65- * Acquires the lock. If the lock is not available, it waits until the lock is released.
69+ * Acquires the lock. If the lock is not available, it waits until the lock is
70+ * released.
6671 */
6772 @ Override
6873 public void lock () {
6974 Thread current = Thread .currentThread ();
7075 // Check for reentrant lock
7176 if (current == owner ) {
77+ holdCount ++;
7278 return ;
7379 }
7480
7581 try {
76- while (!tryLock (1000 , TimeUnit .MILLISECONDS )) {
82+ while (!tryLock (1 , TimeUnit .SECONDS )) {
7783 logger .log (Level .FINE , "Waiting for lock to be released..." );
7884 }
7985 } catch (ApplicationException e ) {
@@ -82,7 +88,8 @@ public void lock() {
8288 }
8389
8490 /**
85- * Attempts to acquire the lock without waiting. Returns true if the lock was acquired successfully.
91+ * Attempts to acquire the lock without waiting. Returns true if the lock was
92+ * acquired successfully.
8693 */
8794 @ Override
8895 public boolean tryLock () {
@@ -99,38 +106,61 @@ public boolean tryLock() {
99106 *
100107 * @param timeout The maximum time to wait for the lock.
101108 * @param unit The time unit of the timeout parameter.
102- * @return True if the lock was acquired successfully within the specified time, false otherwise.
109+ * @return True if the lock was acquired successfully within the specified time,
110+ * false otherwise.
103111 * @throws ApplicationException If an error occurs during lock acquisition.
104112 */
105113 @ Override
106114 public boolean tryLock (long timeout , TimeUnit unit ) throws ApplicationException {
107115 Thread current = Thread .currentThread ();
108- // Check for reentrant lock
109- if (current == owner ) {
110- return true ;
111- }
116+ long deadline = timeout > 0 ? System .nanoTime () + unit .toNanos (timeout ) : 0 ;
117+
118+ while (true ) {
119+ // Check deadline before attempting to acquire
120+ if (timeout > 0 ) {
121+ long remaining = deadline - System .nanoTime ();
122+ if (remaining <= 0 ) {
123+ return false ;
124+ }
125+ }
112126
113- synchronized (this ) {
114- // If the lock is existing, then wait for it to be released.
115- if (watcher . watch ( this ) ) {
116- try {
117- if ( timeout > 0 ) {
118- watcher . waitFor ( this . id , timeout , unit );
119- } else {
120- watcher . waitFor ( this . id );
121- }
122- } catch ( InterruptedException e ) {
123- Thread . currentThread (). interrupt (); // Preserve interrupt status
124- logger . severe ( "Error while waiting for lock: " + e . getMessage ()) ;
125- throw new ApplicationException ( e . getMessage (), e . getCause ()) ;
127+ synchronized (this . id . intern () ) {
128+ // Check for reentrant lock
129+ if (current == owner ) {
130+ holdCount ++;
131+ return true ;
132+ }
133+
134+ // If the lock is not currently held by anyone, acquire it
135+ if (! watcher . watch ( this )) {
136+ this . watcher . register ( this );
137+ this . owner = current ;
138+ this . holdCount = 1 ;
139+ return true ;
126140 }
127141 }
128142
129- // Register the lock and set owner
130- this .watcher .register (this );
131- this .owner = current ;
143+ // Lock is held by another thread - wait outside the synchronized block
144+ if (timeout <= 0 ) {
145+ return false ;
146+ }
147+
148+ long remaining = deadline - System .nanoTime ();
149+ if (remaining <= 0 ) {
150+ return false ;
151+ }
152+
153+ try {
154+ if (!watcher .waitFor (this .id , remaining , TimeUnit .NANOSECONDS )) {
155+ return false ;
156+ }
157+ } catch (InterruptedException e ) {
158+ Thread .currentThread ().interrupt ();
159+ logger .severe ("Error while waiting for lock: " + e .getMessage ());
160+ throw new ApplicationException (e .getMessage (), e .getCause ());
161+ }
162+ // Loop back to try acquiring the lock again
132163 }
133- return true ;
134164 }
135165
136166 /**
@@ -139,20 +169,24 @@ public boolean tryLock(long timeout, TimeUnit unit) throws ApplicationException
139169 @ Override
140170 public void unlock () {
141171 Thread current = Thread .currentThread ();
142- if (owner == null ) return ;
143- if (current != owner ) {
144- throw new IllegalMonitorStateException (
145- "Thread " + current .getName () +
146- " attempting to unlock while not holding the lock"
147- );
148- }
172+ synchronized (this .id .intern ()) {
173+ if (owner == null )
174+ return ;
175+ if (current != owner ) {
176+ throw new IllegalMonitorStateException (
177+ "Thread " + current .getName () +
178+ " attempting to unlock while not holding the lock" );
179+ }
149180
150- try {
151- watcher .unregister (this );
152- owner = null ;
153- } catch (ApplicationException e ) {
154- logger .severe ("Error while unlocking: " + e );
155- throw new ApplicationRuntimeException (e .getMessage (), e .getCause ());
181+ if (--holdCount == 0 ) {
182+ try {
183+ watcher .unregister (this );
184+ owner = null ;
185+ } catch (ApplicationException e ) {
186+ logger .severe ("Error while unlocking: " + e );
187+ throw new ApplicationRuntimeException (e .getMessage (), e .getCause ());
188+ }
189+ }
156190 }
157191 }
158192
@@ -174,8 +208,10 @@ public String id() {
174208 */
175209 @ Override
176210 public boolean equals (Object obj ) {
177- if (this == obj ) return true ;
178- if (obj == null || getClass () != obj .getClass ()) return false ;
211+ if (this == obj )
212+ return true ;
213+ if (obj == null || getClass () != obj .getClass ())
214+ return false ;
179215 DistributedLock other = (DistributedLock ) obj ;
180216 return Objects .equals (id , other .id );
181217 }
0 commit comments