繁体   English   中英

Java中方法参数的线程安全

[英]Thread safety of method parameters in Java

我想知道在 Java 中处理成员参数时线程安全是否已经发挥作用。

假设你有一个 API 的方法

boolean moreThanTen(long value) {
    if(value > 10) return true;
    else return false;
}

这种方法是线程安全的吗?

我想这是因为每个线程都有自己的局部变量堆栈,并且原语都存储在这个局部堆栈中。

唯一让我不确定的是long将是两个单独的读取,因此通常不是线程安全的。

我的问题是:我可以确定方法的参数是原子复制的吗? 因此,当使用原语作为参数(甚至float / long )时,我可以确定在将其复制到局部变量期间线程安全不会成为问题吗?

为了线程不安全,一种方法需要允许多个线程访问共享资源(例如一个字段)。

在您的示例中,没有共享资源(java 按值传递参数),因此该方法不会不安全。

这将是不安全的,因为可以从多个线程访问threshold并且对变量的访问没有正确同步:

  • 一个线程在被另一个线程更新时可能正在读取threshold变量,这可能会导致读取不一致( 长写入不能保证是原子的);
  • 由于缺乏同步,从一个线程写入threshold变量可能无法从另一个线程看到,这可能导致第二个线程读取过时的值。
private long threshold; //mutable, may change

boolean moreThanThreshold(long value) {
  return value > threshold; //side comment: cleaner than your if/else
}
void setThreshold(long t) { this.threshold = t; }

在这种情况下没有线程问题......所有读取都发生在方法自己的堆栈中。 简而言之,即使它们是两次读取……它们发生在堆栈内的一个值上,该值未在其他线程之间共享。

这里有更多关于为什么两次读取不是问题的详细信息。

当向方法传递参数时,我们不是传递引用变量,而是引用变量中位的副本。 像这样的东西:3bad086a。 3bad086a 表示一种获取传递对象的方法。 所以我们只是传递 3bad086a ,它是引用的值。 我们传递的是引用的值,而不是引用本身(而不是对象)。 这个值实际上被复制并提供给方法。 我们总是传递引用值的位的副本! 如果是原始数据类型,这些位将包含原始数据类型本身的值。 如果它是一个对象,这些位将包含告诉 JVM 如何到达该对象的地址值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM