【问题标题】:Concurrent access to a utility static method对实用程序静态方法的并发访问
【发布时间】:2011-07-06 08:21:25
【问题描述】:

我们有一个场景,其中几个线程调用一个静态方法,如下所示:

public static boolean isEmpty(final String s) {
    return s == null || s.length() < 1;
}

100个线程调用会不会导致不一致的问题?

【问题讨论】:

  • s.length() == 0s.length() &lt; 1 便宜,并且字符串的长度不能小于零。
  • @sudocode 或使用String.isEmpty

标签: java multithreading thread-safety


【解决方案1】:

没有。这不会遇到任何并发问题。

1) 你传入的参数是一个String,它是一个不可变的类(它的值不能修改)

2) 该方法不会尝试修改任何共享状态

【讨论】:

  • 如果参数是可变的,是否会有所不同。例如,如果函数签名是:public static boolean isEmpty(String s) { ...}
  • @broadband 通过从参数声明中删除final,您只会使变量s 可变,而不是它所拥有的值——String 的值是不可变的。了解其中的区别很重要。使变量s 可变不会以任何方式影响并发性——对s 的任何重新分配将仅在方法中可见。另一方面,如果参数 s 是某种可变类型,例如ArrayList,如果s 引用了某个列表,那么拥有final 将无助于并发,而该列表可从其他线程访问。
  • 所以在这种情况下基本上可以去掉final关键字,那么保留final关键字有什么意义吗?
  • 也许唯一的原因可能是:变量不能重新绑定以引用另一个对象,但是您可以再次更改 srig 指向的值。
  • @broadband 将方法参数声明为final 的一个很好的理由是避免意外错误,其中作为参数的变量被重新分配给方法主体中的某个其他值,但“认为”为如果它表示传递给方法调用的值。
【解决方案2】:

该方法不访问任何共享状态。因此,不——不会造成任何问题。

【讨论】:

    【解决方案3】:

    不,因为没有共享状态。即使您使用相同的字符串s 调用此方法,它仍然是安全的,因为String 是不可变的并且是线程安全的。

    顺便说一句,Apache Commons 中的 StringUtils.isEmpty() 方法做同样的事情。

    【讨论】:

      【解决方案4】:

      's' 是传递的变量,方法中没有定义任何其他内容,如果有 100 个线程调用它应该没有问题

      【讨论】:

        【解决方案5】:

        所以可以这样想, 每当创建线程时,都会使用自己的堆栈创建它(我猜创建时堆栈的大小约为 2MB)。所以发生的任何执行实际上都发生在这个线程堆栈的上下文中。 创建的任何变量都存在于堆中,但它的引用存在于堆栈中,但不存在于线程堆栈中的静态变量除外。

        您进行的任何函数调用实际上都被推入线程堆栈,无论是静态的还是非静态的。由于完整的方法被压入堆栈,因此发生的任何变量创建都存在于堆栈中(同样例外是静态变量)并且只能由一个线程访问。

        所以所有方法都是线程安全的,直到它们改变某个静态变量的状态。

        【讨论】:

          猜你喜欢
          • 2012-12-17
          • 1970-01-01
          • 1970-01-01
          • 2016-02-25
          • 2014-02-19
          • 1970-01-01
          • 1970-01-01
          • 2011-01-24
          • 1970-01-01
          相关资源
          最近更新 更多