3737import java .util .Random ;
3838import java .util .concurrent .Callable ;
3939import java .util .concurrent .TimeUnit ;
40+ import java .util .concurrent .atomic .AtomicBoolean ;
4041import lombok .EqualsAndHashCode ;
4142import lombok .ToString ;
4243
7071@ Loggable (Loggable .DEBUG )
7172@ ToString
7273@ EqualsAndHashCode (of = { "callable" , "lock" })
74+ @ SuppressWarnings ("PMD.DoNotUseThreads" )
7375public final class Atomic <T > implements Callable <T > {
7476
7577 /**
7678 * Random.
7779 */
7880 private static final Random RANDOM = new SecureRandom ();
7981
82+ /**
83+ * Shutdown hook.
84+ */
85+ private final transient Thread hook = new Thread (
86+ new Runnable () {
87+ @ Override
88+ public void run () {
89+ try {
90+ Atomic .this .lock .unlock ();
91+ } catch (final IOException ex ) {
92+ throw new IllegalStateException (ex );
93+ }
94+ }
95+ }
96+ );
97+
8098 /**
8199 * Callable to use.
82100 */
@@ -92,6 +110,11 @@ public final class Atomic<T> implements Callable<T> {
92110 */
93111 private final transient long max ;
94112
113+ /**
114+ * Successfully locked?
115+ */
116+ private final transient AtomicBoolean locked = new AtomicBoolean ();
117+
95118 /**
96119 * Public ctor (default maximum waiting time of five minutes).
97120 * @param clbl Callable to use
@@ -115,21 +138,8 @@ public Atomic(final Callable<T> clbl, final Lock lck, final long maximum) {
115138 }
116139
117140 @ Override
118- @ SuppressWarnings ("PMD.DoNotUseThreads" )
119141 public T call () throws Exception {
120- final Thread hook = new Thread (
121- new Runnable () {
122- @ Override
123- public void run () {
124- try {
125- Atomic .this .lock .unlock ();
126- } catch (final IOException ex ) {
127- throw new IllegalStateException (ex );
128- }
129- }
130- }
131- );
132- Runtime .getRuntime ().addShutdownHook (hook );
142+ Runtime .getRuntime ().addShutdownHook (this .hook );
133143 long attempt = 0L ;
134144 final long start = System .currentTimeMillis ();
135145 while (!this .lock .lock ()) {
@@ -157,11 +167,11 @@ public void run() {
157167 );
158168 TimeUnit .MILLISECONDS .sleep (delay );
159169 }
170+ this .locked .set (true );
160171 try {
161172 return this .callable .call ();
162173 } finally {
163- this .lock .unlock ();
164- Runtime .getRuntime ().removeShutdownHook (hook );
174+ this .unlock ();
165175 }
166176 }
167177
@@ -180,4 +190,15 @@ public T callQuietly() {
180190 }
181191 }
182192
193+ /**
194+ * Unlock it.
195+ * @throws IOException If fails
196+ */
197+ private void unlock () throws IOException {
198+ if (this .locked .get ()) {
199+ this .lock .unlock ();
200+ }
201+ Runtime .getRuntime ().removeShutdownHook (this .hook );
202+ }
203+
183204}
0 commit comments