如果非同步静态方法不修改静态类变量,那么它们是否安全?

时间:2011-03-02 21:00:29

标签: java multithreading concurrency static thread-safety

我想知道你是否有一个同步的静态方法,但修改任何静态变量是否是线程安全的?如果方法在其中创建局部变量怎么办?例如,以下代码是否是线程安全的?

public static String[] makeStringArray( String a, String b ){
    return new String[]{ a, b };
}

所以,如果我有两个线程连续和同时调用这个方法,一个有狗(说“大丹狗”和“斗牛犬”)而另一个有猫(说“波斯语”和“暹罗语”)我会得到猫和狗在同一个阵列?或者猫和狗不会同时在同一个方法的调用内?

5 个答案:

答案 0 :(得分:206)

这种方法是100%线程安全的,即使它不是static也是如此。当您需要在线程之间共享数据时,会出现线程安全问题 - 您必须注意原子性,可见性等。

此方法仅对驻留在堆栈上的参数进行操作,并对堆上的不可变对象进行引用。 堆栈本身就是线程的本地,因此不会发生数据共享。

不可变对象(在这种情况下为String)也是线程安全的,因为一旦创建它们就无法更改,并且所有线程都看到相同的值。另一方面,如果该方法接受(可变)Date,您可能会遇到问题。两个线程可以同时修改同一个对象实例,从而导致竞争条件和可见性问题。

答案 1 :(得分:28)

方法在更改某些共享状态时只能是线程不安全的。它是静态的还是无关紧要的。

答案 2 :(得分:12)

该功能完全是线程安全的。

如果你考虑一下......假设如果不同会发生什么。如果不同步,每个常用函数都会出现线程问题,因此JDK中的所有API函数都必须同步,因为它们可能被多个线程调用。由于应用程序大部分时间都在使用某些API,因此多线程应用程序实际上是不可能的。

考虑到这一点太荒谬了,所以只为你自己:如果有明显的理由可以解决问题,那么方法就不是线程安全的。试着总是考虑一下如果我的函数中有多个线程会怎么样,如果你有一个步进调试器并且一个接一个地推进第一个...然后第二个线程...也许第二个线程......会有问题吗?如果你找到一个,它不是线程安全的。

请注意,大多数Java 1.5 Collection类都不是线程安全的,除了陈述的那些,如ConcurrentHashMap。

如果您真的想深入了解这一点,请仔细查看volatile关键字及其所有副作用。看一下Semaphore()和Lock()类,以及他们在java.util.Concurrent中的朋友。阅读课程周围的所有API文档。值得学习和满足。

对于这个过于精细的答案感到抱歉。

答案 3 :(得分:1)

static关键字与synchronized静态方法一起使用,以修改线程间共享的静态数据。使用static关键字创建的所有线程都将争用该方法的单个版本。

使用volatile关键字和synchronized实例方法将保证每个线程都有自己的共享数据副本,并且线程之间不会发生读/写泄漏。

答案 4 :(得分:0)

不可变的字符串对象是上述线程安全方案的另一个原因。相反,如果使用可变对象(比如makeMutableArray ..)那么线程安全肯定会破坏。