Tapas Bose
Tapas Bose

Reputation: 29806

How to ensure thread safety of utility static method?

Is there any general way or rule existing by which we can ensure the thread safety of static methods specifically used in various Utility classes of any applications? Here I want to specifically point out the thread safety of Web Applications.

It is well known that static methods with Immutable Objects as parameters are thread safe and Mutable Objects are not.

If I have a utility method for some manipulation with java.util.Date and that method accepts an instance of java.util.Date, then this method is not thread safe. Then how to make it thread safe without changing the way of parameter passing?

public class DateUtils {

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

Also is the class javax.faces.context.FacesContext mutable? Is it thread safe to pass an instance of this class to such static utility method?

This list of classes, instances of which can be or cannot be passed as parameters, could be long; so what points should we keep in mind while writing codes of such utility classes?

Upvotes: 97

Views: 91845

Answers (8)

Stephen C
Stephen C

Reputation: 718788

There is no way to make an arbitrary static method unconditionally thread-safe.

Some methods are inherently thread-safe. For example:

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

is unconditionally thread-safe because String and all operations on String are thread-safe.

However, your example

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

cannot be unconditionally thread-safe.

In this case, the problem is that Date class is not thread-safe.

  1. It has setXxx methods that mutate a date object's fields.
  2. Even the getXxx methods can cause the date's state to change. (Read the source code, and look at the normalize() method and where it is called!)
  3. None of Date's public methods are declared as synchronized or use synchronized blocks.

Because of 1), there is nothing that your method could do to stop some other thread from changing date while the method call is happening. Then, because of 2) and 3), the thread calling getNormalizedDate is not even guaranteed to see the latest state of date.


Is this a problem? Well, maybe not. It depends on how the application as a whole handles the Date objects. For example, if Date objects are created in normalized form, safely published and your application then doesn't call any of the set methods ... you should be able to handle Date objects in a thread-safe fashion.

(Among other things, that implies that your getNormalizeDate method should not do anything that would mutate its date argument.)

But there is a better way. Replace Date with the corresponding java.time.* class; e.g. LocalDateTime or ZonedDateTime. These classes were introduced in Java 8, and they are specified to be immutable and thread-safe.


I concur with Duncan Jones answer. Anyone who finds themselves asking a question like this one needs to read a good book on Java Concurrency. This is not a topic where you can rely on your intuition, or on stuff that you read in some blog post or (low quality) tutorial.

The text that he recommends is ~400 pages, and is (IMO) well worth the investment. Even though it was published nearly 20 years ago.

Upvotes: 1

SRK
SRK

Reputation: 158

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

Upvotes: 6

swayamraina
swayamraina

Reputation: 3158

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.

Upvotes: 16

PMorganCA
PMorganCA

Reputation: 760

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.

Upvotes: 9

rohith
rohith

Reputation: 753

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

Upvotes: 17

assylias
assylias

Reputation: 328598

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.

Upvotes: 31

Duncan Jones
Duncan Jones

Reputation: 69339

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.

Upvotes: 104

R Kaja Mohideen
R Kaja Mohideen

Reputation: 917

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());
    // ...
}

Upvotes: 9

Related Questions