void (Throwable throwable) { ApplierCompleter<T> a = this; ApplierCompleter<T> child = a; while (true) { // update parent.throwable in a thread safe way Throwable oldThrowable; Throwable newThrowable; do { oldThrowable = a.throwable; newThrowable = moreImportant(oldThrowable, throwable); } while (oldThrowable != newThrowable && !throwableUpdater.compareAndSet(a, oldThrowable, newThrowable)); throwable = newThrowable; if (a.getPendingCount() == 0) { // currently avoid using onExceptionalCompletion since it leaks exceptions via ForkJoinTask.exceptionTable a.onCompletion(child); //a.onExceptionalCompletion(throwable, child); child = a; //noinspection unchecked a = (ApplierCompleter<T>)a.getCompleter(); if (a == null) { // currently avoid using completeExceptionally since it leaks exceptions via ForkJoinTask.exceptionTable child.quietlyComplete(); break; } } else if (a.decrementPendingCountUnlessZero() != 0) { break; } } }