Java中方法参数的线程安全性

时间:2016-06-27 15:07:18

标签: java multithreading concurrency parameter-passing

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

假设你有一个API的方法

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

这种方法是否可以线程安全?

我想它会因为每个线程都有自己的局部变量堆栈,并且基元都存储在这个本地堆栈中。

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

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

感谢。

2 个答案:

答案 0 :(得分:8)

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

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

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

  • 一个线程在被另一个线程更新时可能正在读取threshold变量,这可能导致读取不一致(long writes are not guaranteed to be atomic);和
  • 由于缺少同步,可能无法从另一个线程向一个线程写入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; }

答案 1 :(得分:1)

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

以下是有关为什么两次读取不成问题的更详细信息。

将参数传递给方法时,我们不传递引用变量,而是传递引用变量中的位副本。  像这样:3bad086a。 3bad086a代表了一种获取传递对象的方法。所以我们只是传递3bad086a,它是参考的价值。 我们传递引用的值而不是引用本身(而不是对象)。该值实际上是COPIED并赋予方法。我们总是传递一份参考值的副本!  如果它是原始数据类型,则这些位将包含原始数据类型本身的值。如果它是一个Object,那么这些位将包含告诉JVM如何到达Object的地址值。