如何保证实用静态方法的线程安全?

是否有任何通用的方法或规则可以确保在任何应用程序的各种实用程序类中专门使用的静态方法的线程安全性。这里我想特别指出 Web 应用程序的线程安全性。

众所周知,以不可变对象为参数的静态方法是线程安全的,而可变对象则不是。

如果我有一个对 java.util.Date进行某种操作的实用方法,并且该方法接受 java.util.Date的一个实例,那么这个方法将不是线程安全的。那么如何在不改变参数传递方式的情况下保证线程安全呢?

public class DateUtils {


public static Date getNormalizeDate(Date date) {
// some operations
}
}

javax.faces.context.FacesContext也是可变的吗?将此类的实例传递给这种静态实用工具方法是否线程安全?

这些类的实例可以或不能作为参数传递,这个列表可能很长; 那么在编写这些实用程序类的代码时,我们应该记住哪些要点呢?

77955 次浏览

I would recommend creating a copy of that (mutable) object as soon as the method starts and use the copy instead of original parameter.

Something like this

public static Date getNormalizeDate(Date date) {
Date input = new Date(date.getTime());
// ...
}

Since your class does not hold any member variables, your method is stateless (it only uses local variables and the argument) and therefore is thread safe.

The code that calls it might not be thread safe but that's another discussion. For example, Date not being thread safe, if the calling code reads a Date that has been written by another thread, you must use proper synchronization in the Date writing and reading code.

It is well known that static methods with immutable objects as parameters are thread safe and mutable objects are not.

I would contest this. Arguments passed to a method are stored on a stack, which is a per-thread idiom.

If your parameter is a mutable object such as a Date then you need to ensure other threads are not modifying it at the same time elsewhere. But that's a different matter unrelated to the thread-safety of your method.

The method you posted is thread-safe. It maintains no state and operates only on its arguments.

I would strongly recommend you read Java Concurrency in Practice, or a similar book dedicated to thread safety in Java. It's a complex subject that cannot be addressed appropriately through a few StackOverflow answers.

Given the structure of the JVM, local variables, method parameters, and return values are inherently "thread-safe." But instance variables and class variables will only be thread-safe if you design your class appropriately. more here

Here's how I think of it: imagine a CampSite (that's a static method). As a camper, I can bring in a bunch of objects in my rucksack (that's arguments passed in on the stack). The CampSite provides me with a place to put my tent and my campstove, etc, but if the only thing the CampSite does is allow me to modify my own objects then it's threadsafe. The CampSite can even create things out of thin air (FirePit firepit = new FirePit();), which also get created on the stack.

At any time I can disappear with all my objects in my ruckstack and one of any other campers can appear, doing exactly what they were doing the last time they disappeared. Different threads in this CampSite will not have access to objects on the stack created CampSite in other threads.

Say there's only one campStove (a single object of CampStove, not separate instantiations). If by some stretch of the imagination I am sharing a CampStove object then there are multi-threading considerations. I don't want to turn on my campStove, disappear and then reappear after some other camper has turned it off - I would forever be checking if my hot dog was done and it never would be. You would have to put some synchronization somewhere... in the CampStove class, in the method that was calling the CampSite, or in the CampSite itself... but like Duncan Jones says, "that's a different matter".

Note that even if we were camping in separate instantiations of non-static CampSite objects, sharing a campStove would have the same multi-threading considerations.

I see a lot of answers but none really pointing out the reason.

So this can be thought like this, Whenever a thread is created, it is created with its own stack (I guess the size of the stack at the time of creation is ~2MB). So any execution that happens actually happens within the context of this thread stack. Any variable that is created lives in the heap but it's reference lives in the stack with the exceptions being static variables which do not live in the thread stack.

Any function call you make is actually pushed onto the thread stack, be it static or non-static. Since the complete method was pushed onto the stack, any variable creation that takes place lives within the stack (again exceptions being static variables) and only accessible to one thread.

So all the methods are thread safe until they change the state of some static variable.

We will take some examples to see if static method is Thread-Safe or not.

Example 1:

public static String concat (String st1, String str2) {
return str1 + str2
}

Now above method is Thread Safe.

Now we will see another example which is not thread-safe.

Example 2:

 public static void concat(StringBuilder result, StringBuilder sb, StringBuilder sb1) {
result.append(sb);
result.append(sb1);
}

If you see both methods are very very primitive but still one is thread safe and other one is not. Why? What difference both having?

Are static methods in utilities prone to non thread-safe? Lot’s of questions right?

Now every thing depends on how you implement method & which type of objects you are using in your method. Are you using thread safe objects? Are these objects / classes are mutable?

If you see in Example 1 arguments of concat method are of type String which are immutable and passed by value so this method is completely thread-safe.

Now in Example 2 arguments are of StringBuilder type which are mutable so other thread can change value of StringBuilder which makes this method is potentially non thread-safe.

Again this is not completely true. If you are calling this utility method with local variables then you never having any problem related to thread-safety. Because each thread uses it’s own copy for local variables so you never run into any thread safety issues. But that is beyond scope of above static method. It’s depend on calling function / program.

Now static methods in utility class are kind of normal practice. So how we can avoid it? If you see Example 2 I am modifying 1st parameter. Now if you want to make this method really thread safe then one simple thing you can do. Either use non-mutable variables / objects or do not change / modify any method parameters.

In Example 2 we already used StringBuilder which is mutable so you can change implementation to make static method thread safe as follows:

public static String concat1(StringBuilder sb, StringBuilder sb1) {
StringBuilder result = new StringBuilder();
result.append(sb);
result.append(sb1);
return result.toString();
}

Again going to basics always remember if you are using immutable objects & local variables then you are miles away from thread safety issues.

From the arcticle(https://nikhilsidhaye.wordpress.com/2016/07/29/is-static-method-in-util-class-threadsafe/)Thank you Nikhil Sidhaye for this simple article