private void doRunFinalization( final AtomicReference<TransactionResult<T>> transactionId, final boolean innerCall, final TransactionResult.Reason reason, final T transactionResult, final ContextCallback<T> callback) { repetitiousTaskManager.cancelTask(transactionId); synchronized (mutex) { // this code may be called from three points: // 1. On latch TIMEOUT. In that case first coming thread sets the default return value, runs // finalization routine and awaits it finishes. // 2. On shutdown call. In that case calling thread set the default return value, runs // finalization routine and returns. // 3. On release call. In that case calling thread set the return value equals to the value // passed by calling thread, runs finalization routine and returns. final boolean trnsIdEmpty = transactionId.compareAndSet( null, transactionResult == null ? new TransactionResultImpl<T>(initialValue, reason) : new TransactionResultImpl<T>(transactionResult, reason)); if (trnsIdEmpty) { // flag whether we go through 1. scenario // create new finalization routine final FutureTask<Object> futureTask = new FutureTask<Object>( new Runnable() { public void run() { // run outer finalization routine // Thread.currentThread().setName("Transaction finalizator"); try { callback.finalizeTransaction(transactionId.get()); } catch (Exception e) { e.printStackTrace(); } finally { // let this iteration awaiting threads to be free and continue execution cleanUpFinalization(transactionId); } } }, null); // hold and execute new finalization routine finalizationMap.put(transactionId, futureTask); // TransactionUtils.getExecutorService().execute(futureTask); TransactionUtils.invokeLaterSmart( new TransactionRunnable("SynchronizationContext.doRunFinalization()") { public void run() { if (!futureTask.isCancelled() && !futureTask.isDone()) { futureTask.run(); futureTask.cancel(true); } } }); // set free waiting thread and initiate new iteration doReleaseThreads(); } } // here one more synchronization point for awaiting threads from this iteration // this time threads waiting till the end of finalization routine. // All outer threads (shutdown(), release()) do not block here if (innerCall) { boolean needCleanupFinalization = false; // for all separate transaction we have separate transactionId. //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (transactionId) { long startWait = System.currentTimeMillis(); // waiting here until finalization task is done. Finalization task clears the map by itself // threads do not wait more then FINALIZATION_TIMEOUT*2 while (finalizationMap.containsKey(transactionId)) { try { assert !TransactionUtils.isTransactionExecutionThread() : "Task queue blocking task detected"; transactionId.wait(FINALIZATION_TIMEOUT); } catch (InterruptedException e) { Thread.interrupted(); } if ((System.currentTimeMillis() - startWait) >= FINALIZATION_TIMEOUT) { needCleanupFinalization = true; break; } } } // if something happens to finalization routine (helper theread abruptly dead or something // like that) we make map clean up. // and try to notify all awaitng threads if (needCleanupFinalization) { Logger.log( "Warning!!! transaction finalization took too long time. More than " + FINALIZATION_TIMEOUT + " millis"); cleanUpFinalization(transactionId); } } }