微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么Throwable类的以下方法需要同步?

如何解决为什么Throwable类的以下方法需要同步?

private StackTraceElement[] stackTrace = UNASSIGNED_STACK;
private transient Object backtrace;

private synchronized StackTraceElement[] getourStackTrace() {
    // Initialize stack trace field with information from
    // backtrace if this is the first call to this method
    if (stackTrace == UNASSIGNED_STACK ||
        (stackTrace == null && backtrace != null) /* Out of protocol state */) {
        int depth = getStackTraceDepth();
        stackTrace = new StackTraceElement[depth];
        for (int i=0; i < depth; i++)
            stackTrace[i] = getStackTraceElement(i);
    } else if (stackTrace == null) {
        return UNASSIGNED_STACK;
    }
    return stackTrace;
}

public synchronized Throwable fillInStackTrace() {
    if (stackTrace != null ||
        backtrace != null /* Out of protocol state */ ) {
        fillInStackTrace(0);
        stackTrace = UNASSIGNED_STACK;
    }
    return this;
}

public synchronized Throwable fillInStackTrace() {
    if (stackTrace != null ||
        backtrace != null /* Out of protocol state */ ) {
        fillInStackTrace(0);
        stackTrace = UNASSIGNED_STACK;
    }
    return this;
}

以上代码为jdk源码

jdk 版本:1.8.0_144

异常栈不应该是线程私有的吗?为什么需要同步控制?

解决方法

为什么Throwable类的以下方法需要同步?

出于正常原因。可能存在两个线程同时执行触发这些调用中的任何一个的操作的情况。如果它们不是 synchronized,则可能会导致竞争条件或内存异常。

(请注意,stacktracebacktrace 都不是 volatile,因此如果代码测试和/或从多个线程分配它们,则某些线程可能会看到过时的值。)

现在对所有可能的代码路径进行深入分析可能表明,如果不声明这些方法 synchronized,此代码将是线程安全的。但如果是我编写代码,我可能还是会使用 synchronized,因为:

  • 在这里使用synchronized显然是安全的,并且
  • 相对于捕获异常的堆栈跟踪时发生的所有其他事情,(可能是不必要的)互斥锁的开销很小,并且
  • 异常应该很少出现……除非程序错误地使用了异常。

如果获取异常的堆栈跟踪不是线程安全的,那将是不可接受的。如果堆栈跟踪不可靠,调试 Java 将完全是“废话”。这是代码必须是线程安全的情况之一,即使规范(javadoc)对此保持沉默。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。