code: private Throwable getThrowableException() {
      int h = System.identityHashCode(this);
      ExceptionNode e;
      final ReentrantLock lock = exceptionTableLock;
      lock.lock();
      try {
        expungeStaleExceptions();
        ExceptionNode[] t = exceptionTable;
        e = t[h & (t.length - 1)];
        while (e != null && e.get() != this)
          e = e.next;
      } finally {
        lock.unlock();
      }
      Throwable ex;
      if (e == null || (ex = e.ex) == null)
        return null;
      if (e.thrower != Thread.currentThread().getId()) {
        try {
          Constructor<?> noArgCtor = null;
          // public ctors only
          for (Constructor<?> c : ex.getClass().getConstructors()) {
            Class<?>[] ps = c.getParameterTypes();
            if (ps.length == 0)
              noArgCtor = c;
            else if (ps.length == 1 && ps[0] == Throwable.class)
              return (Throwable) c.newInstance(ex);
          }
          if (noArgCtor != null) {
            Throwable wx = (Throwable) noArgCtor.newInstance();
            wx.initCause(ex);
            return wx;
          }
        } catch (Exception ignore) {
        }
      }
      return ex;
    }
docs: Returns a rethrowable exception for this task, if available. To provide accurate stack traces,
  if the exception was not thrown by the current thread, we try to create a new exception of the
  same type as the one thrown, but with the recorded exception as its cause. If there is no such
  constructor, we instead try to use a no-arg constructor, followed by initCause, to the same
  effect. If none of these apply, or any fail due to other exceptions, we return the recorded
  exception, which is still correct, although it may contain a misleading stack trace.
  
  @return the exception, or null if none