How to ensure thread safety of utility static method?
是否有任何通用的方法或规则出口,通过这些方法我们可以确保在任何应用程序的各种实用程序类中专门使用的静态方法的线程安全。这里我想特别指出Web应用程序的线程安全性。
众所周知,使用不可变对象作为参数的静态方法是线程安全的,而可变对象则不是。
如果我有一个对
1 2 3 4 5 6 |
类
这些类的实例可以作为参数传递,也可以不作为参数传递,它们的列表可能很长;所以在编写此类实用程序类的代码时,我们应该记住哪些要点?
It is well known that static methods with immutable objects as parameters are thread safe and mutable objects are not.
我会反对这个。传递给方法的参数存储在堆栈中,这是一种每线程的习惯用法。
如果您的参数是一个可变的对象,如
您发布的方法是线程安全的。它不维护任何状态,只对其参数进行操作。
我强烈建议您在实践中阅读Java并发,或者类似于爪哇的线程安全的类似书籍。这是一个复杂的主题,不能通过几个stackoverflow答案来适当地解决。
由于类不包含任何成员变量,因此方法是无状态的(它只使用局部变量和参数),因此是线程安全的。
调用它的代码可能不是线程安全的,但这是另一个讨论。例如,日期不是线程安全的,如果调用代码读取另一个线程已写入的日期,则必须在日期写入和读取代码中使用适当的同步。
考虑到JVM的结构,局部变量、方法参数和返回值本质上是"线程安全的"。但是,只有在适当地设计类时,实例变量和类变量才是线程安全的。这里更多
我是这样想的:想象一个营地(这是一个静态方法)。作为一个野营者,我可以把一堆东西放在背包里(这是堆栈上传递的参数)。营地为我提供了一个放置帐篷和露营炉等的地方,但是如果营地唯一能做的就是允许我修改自己的物品,那么它就是线程安全。营地甚至可以用稀薄的空气(
任何时候,我都可以带着我所有的东西消失在背包里,任何一个露营者都可以出现,做他们上次消失时做的事情。此campsite中的不同线程将无法访问在其他线程中创建的堆栈上的campsite对象。
假设只有一个露营炉(一个单一的露营炉对象,而不是单独的实例化)。如果通过某种程度的想象,我共享一个camphove对象,那么就需要考虑多线程。我不想打开我的露营炉,消失了,然后在其他露营者关掉它后重新出现-我将永远检查我的热狗是否做了,它永远不会。您必须在某个地方放置一些同步…在camphove类中,在调用campsite的方法中,或者在campsite本身中…但正如邓肯·琼斯所说,"那是另一回事"。
请注意,即使我们在非静态营地对象的单独实例化中露营,共享一个露营炉也会有相同的多线程考虑。
我建议在方法启动后立即创建该(可变)对象的副本,并使用副本而不是原始参数。
像这样的东西
1 2 3 4 |
我看到了很多答案,但没有一个真正指出原因。
所以可以这样想,每当创建线程时,它都是用自己的堆栈创建的(我猜创建时堆栈的大小是~2MB)。所以任何执行实际上都发生在这个线程栈的上下文中。创建的任何变量都存在于堆中,但其引用却存在于堆栈中,但不存在于线程堆栈中的静态变量除外。
您所做的任何函数调用实际上都被推送到线程堆栈上,不管是静态的还是非静态的。因为完整的方法被推到堆栈上,所以发生的任何变量创建都会在堆栈中(同样是静态变量的异常),并且只能被一个线程访问。
所以所有的方法在改变某个静态变量的状态之前都是线程安全的。