Skip to content

Commit 2ea08c0

Browse files
committed
Exclude calling of enable/disable consumers from syncronized block to avoid deadlocks if a consumer is blocking on a different thread
1 parent a03e15e commit 2ea08c0

File tree

1 file changed

+31
-27
lines changed

1 file changed

+31
-27
lines changed

src/main/java/de/bluecolored/bluemap/api/BlueMapAPI.java

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,13 @@ public static synchronized Optional<BlueMapAPI> getInstance() {
161161
* <p>The {@link Consumer}s are guaranteed to be called in the order they were registered in.</p>
162162
* @param consumer the {@link Consumer}
163163
*/
164-
public static synchronized void onEnable(Consumer<BlueMapAPI> consumer) {
165-
onEnableConsumers.add(consumer);
166-
if (BlueMapAPI.instance != null) consumer.accept(BlueMapAPI.instance);
164+
public static void onEnable(Consumer<BlueMapAPI> consumer) {
165+
BlueMapAPI api;
166+
synchronized (BlueMapAPI.class) {
167+
onEnableConsumers.add(consumer);
168+
api = BlueMapAPI.instance;
169+
}
170+
if (api != null) consumer.accept(BlueMapAPI.instance);
167171
}
168172

169173
/**
@@ -192,55 +196,55 @@ public static synchronized boolean unregisterListener(Consumer<BlueMapAPI> consu
192196
* Used by BlueMap to register the API and call the listeners properly.
193197
* @param instance the {@link BlueMapAPI}-instance
194198
* @return <code>true</code> if the instance has been registered, <code>false</code> if there already was an instance registered
195-
* @throws ExecutionException if a listener threw an exception during the registration
199+
* @throws Exception if a listener threw an exception during the registration
196200
*/
197201
@ApiStatus.Internal
198-
protected static synchronized boolean registerInstance(BlueMapAPI instance) throws Exception {
199-
if (BlueMapAPI.instance != null) return false;
200-
201-
BlueMapAPI.instance = instance;
202-
203-
List<Exception> thrownExceptions = new ArrayList<>(0);
202+
protected static boolean registerInstance(BlueMapAPI instance) throws Exception {
203+
List<Consumer<BlueMapAPI>> consumersToCall;
204204

205-
for (Consumer<BlueMapAPI> listener : BlueMapAPI.onEnableConsumers) {
206-
try {
207-
listener.accept(BlueMapAPI.instance);
208-
} catch (Exception ex) {
209-
thrownExceptions.add(ex);
210-
}
205+
synchronized (BlueMapAPI.class) {
206+
if (BlueMapAPI.instance != null) return false;
207+
BlueMapAPI.instance = instance;
208+
consumersToCall = List.copyOf(onEnableConsumers);
211209
}
212210

213-
return throwAsOne(thrownExceptions);
211+
return callConsumers(instance, consumersToCall);
214212
}
215213

216214
/**
217215
* Used by BlueMap to unregister the API and call the listeners properly.
218216
* @param instance the {@link BlueMapAPI} instance
219217
* @return <code>true</code> if the instance was unregistered, <code>false</code> if there was no or another instance registered
220-
* @throws ExecutionException if a listener threw an exception during the un-registration
218+
* @throws Exception if a listener threw an exception during the un-registration
221219
*/
222220
@ApiStatus.Internal
223-
protected static synchronized boolean unregisterInstance(BlueMapAPI instance) throws Exception {
224-
if (BlueMapAPI.instance != instance) return false;
221+
protected static boolean unregisterInstance(BlueMapAPI instance) throws Exception {
222+
List<Consumer<BlueMapAPI>> consumersToCall;
225223

226-
List<Exception> thrownExceptions = new ArrayList<>(0);
224+
synchronized (BlueMapAPI.class) {
225+
if (BlueMapAPI.instance != instance) return false;
226+
BlueMapAPI.instance = null;
227+
consumersToCall = List.copyOf(onEnableConsumers);
228+
}
229+
230+
return callConsumers(instance, consumersToCall);
231+
}
227232

228-
for (Consumer<BlueMapAPI> listener : BlueMapAPI.onDisableConsumers) {
233+
private static boolean callConsumers(BlueMapAPI instance, List<Consumer<BlueMapAPI>> consumers) throws Exception {
234+
List<Exception> thrownExceptions = new ArrayList<>(0);
235+
for (Consumer<BlueMapAPI> consumer : consumers) {
229236
try {
230-
listener.accept(BlueMapAPI.instance);
237+
consumer.accept(instance);
231238
} catch (Exception ex) {
232239
thrownExceptions.add(ex);
233240
}
234241
}
235-
236-
BlueMapAPI.instance = null;
237-
238242
return throwAsOne(thrownExceptions);
239243
}
240244

241245
private static boolean throwAsOne(List<Exception> thrownExceptions) throws Exception {
242246
if (!thrownExceptions.isEmpty()) {
243-
Exception ex = thrownExceptions.get(0);
247+
Exception ex = thrownExceptions.getFirst();
244248
for (int i = 1; i < thrownExceptions.size(); i++) {
245249
ex.addSuppressed(thrownExceptions.get(i));
246250
}

0 commit comments

Comments
 (0)