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);
      }
    }
  }