5

I have the following code

//EDIT :- updated code with @Riaz's answer ( this code should be thread -safe now )

public final class MyClass
{
    private static MyClass2 _class2;
    private MyClass()
    {

    }

    public static synchronized  MyClass CreateMyClass1(String arg0 , ArrayList<MyClass3> class3) throws Exception
    {
        MyClass myClass = new MyClass();        
        _class2 = new Class2(arg0 , class3);
        return myClass;
    }

    public static synchronized  MyClass CreateMyClass2(InputStream arg0 , ArrayList<MyClass3> class3) throws Exception
    {
        MyClass myClass = new MyClass();        
        _class2 = new Class2(arg0 , class3);
        return myClass;
    }

    //EDIT :- added a third method that accesses methods of the _class2 object
    public Object getSomething() //don't need synchronized for methods that don't change the state of the object
    { 
       return MyClass._class2.someMethod();
    }

    public synchronized  Object doSomethingToClass2() 
    { 
       //change state of the _class2 variable 
    }
}

I have read a few posts explaining thread safety for static methods but I have a few questions:

  1. From what I understand, unless two threads can change the state of a shared mutable object, I don't need to worry about thread safety. (Assuming that I am not leaking the "this" reference.)

    So when using MyClass, can thread1 call CreateMyClass1 and thread2 call CreateMyClass2 which will mean that the _class2 variable will be changed by thread2 which is what I want to avoid. Will making _class2 as volatile prevent this? If yes, I am not sure how static volatile will be interpreted by the JVM? Will this be enough to make MyClass thread-safe?

  2. Does returning an object of the MyClass class in both the static methods cause any violation of thread-safety?

user2912902
  • 327
  • 1
  • 7
  • 17

4 Answers4

1

So when using MyClass , can thread1 call CreateMyClass1 and thread2 call CreateMyClass2 which will mean that the _class2 variable will be changed by thread2 which is what i want to avoid.

Static variables are effectively shared between threads. However, the change in one thread won't be automatically be seen by other threads. Declaring the variable as volatile guarantee the visibility.

I am not sure how static volatile will be interpreted by the JVM?

Here a paste from the JVM spec that explain it all and confirm your understanding.

ACC_VOLATILE 0x0040 Declared volatile; cannot be cached.

In respective order, the parameters are flag name, value, interpretation.

Does returning an object of the MyClass class in both the static methods cause any violation of thread-safety?

Not at all you instantiate the object in the method scope, it will be handled as any other object.


More details about thread safety that might be useful

  • Each thread has it own stacks.
  • Local variable are added to stacks and automatically thread-safe.
  • The problem with thread safety is when you try to share data between them, which is not the case here.
  • If you want to share simple values between multiple thread, you might want to have a look to atomic variables instead of using the synchronized keyword.
  • Whether the data is static or not make no difference, problems only come when sharing.
  • When adding synchronized to a static method, the Class object will be locked.
Jean-François Savard
  • 20,626
  • 7
  • 49
  • 76
1

static means not associated with an instance of the containing class. This means all your objects (and static methods) share the same variable.

volatile simply means that the value may be changed by other threads without warning.

Declaring a variable as volatile (be it static or not) states that the variable will be accessed frequently by multiple threads. In Java, this boils down to instructing threads that they can not cache the variable's value, but will have to write back immediately after mutating so that other threads see the change. (Threads in Java are free to cache variables by default).

so the effect of these two modifiers are completely orthogonal. you can initialize the variable as static volatile

Swathi
  • 602
  • 4
  • 17
1

Consider what the various keywords do/mean;

volatile - it guarantees that any thread that reads the field will see the most up-to-date/recently written value (this is only useful if you have mutable data you need to share)

synchronized - obtains a lock on what is synchronized so that other threads cannot do anything until the thread that has the lock is finished doing what it needs

Given that your CreateMyClass1 and CreateMyClass2 methods both re-assign _class2 to a new instance of MyClass2 it is possible for different threads to change _class2.

If you wanted to have a separate value for each thread you could consider looking at ThreadLocal. Perhaps using a static ThreadLocal might suit your needs;

private static ThreadLocal<MyClass> threadLocal = new ThreadLocal<MyClass>();

This would replace private static MyClass2 _class2;

Then in create methods you can set each threads MyClass2;

public static MyClass CreateMyClass1(String arg0 , ArrayList<MyClass3> class3) throws Exception
{
    Test myClass = new Test();        
    threadLocal.set(new MyClass2(arg0 , class3));
    return myClass;
}

All you then have to do to get each threads MyClass2 is use the threadLocal.get() method and you will have that current threads MyClass2. This removes the worry of a different thread changing the value since each thread has its own.

I hope this is somewhat helpful and please tell me if I've misinterpreted your question :)

kstandell
  • 775
  • 6
  • 16
1

This implementation could be a nice bad example in an exam or interview question on multi-threading!

Before answering your questions, here are three points:

I.) A final class cannot be extended. It does not at all imply that instances of the class are immutable. So it's a red herring as far the issue of multithreading here.

II.) CreateMyClass1/2 have the same implementation, violating my favorite coding principle Don't Repeat Yourself (DRY). In general you would use the keyword synchronized to prevent a method from being called simultaneously by different threads then you only need one method. The synchronized keyword prevents the _class2 variable from being interleaved by the two threads:

public static synchronized MyClass CreateMyClass(InputStream arg0 , ArrayList<MyClass3> class3) throws Exception{ MyClass myClass = new MyClass();
_class2 = new Class2(arg0 , class3); return myClass; }

III.) A tighter approach would be to use a synchronized block around the class variable, since the only shared variable you need to protect is the static _class2 variable, and it is a class resource. The local variable(s) myClass is not shared between separate threads so you do not need to fear its being interleaved:
public static MyClass CreateMyClass(InputStream arg0 , ArrayList<MyClass3> class3) throws Exception { MyClass myClass = new MyClass(); synchronized (MyClass.class){ _class2 = new Class2(arg0 , class3); }; return myClass; }

Now your questions:
1)

Unless two threads can change the state of a shared mutable object , i don't need to worry about thread safety

  • correct.

So when using MyClass , can thread1 call CreateMyClass1 and thread2 call CreateMyClass2 which will mean that the _class2 variable will be changed by thread2 which is what i want to avoid. Will making _class2 as volatile prevent this? If yes , I am not sure how static volatile will be interpreted by the JVM? Will this be enough to make MyClass thread-safe?

  • the static _class2 variable will be changed by subsequent invocations of the static method CreateMyClass. That is the only sensible outcome of running the code. If instead you want to avoid interleaving the assignment of _class2 to prevent it from getting into a bad state, due to the method getting called by different threads, then yes, volatile will fix this problem, and also fix your multithreading issues (as far as this snippet goes), enabling the removal of the synchronized block:
    public final class MyClass { private static volatile MyClass2 _class2; public static MyClass CreateMyClass(String arg0 , ArrayList<MyClass3> class3) throws Exception { MyClass myClass = new MyClass(); _class2 = new Class2(arg0 , class3); return myClass; } }

However, any other MyClass methods that subsequently use non-mutable methods of _class2, will not be thread-safe. Since volatile only synchronizes assignment of _class2.

2)
No. myClass is a local variable.

Rian Rizvi
  • 9,989
  • 2
  • 37
  • 33
  • both methods CreateMyClass1 and CreateMyClass2 will have to be separate because I am passing different arguments to both the methods . One accepts string , the other one accepts an inputstream and there might be a third/fourth one in the future as well. So as far i understood , i will add the volatile keyword and make both the methods as synchronized ..right? Also as you mentioned "However, any other MyClass methods that subsequently use non-mutable methods of _class2, will not be thread-safe" , i will need to make these methods(which use methods of_class2 ) synchronized as well , right? – user2912902 Mar 12 '15 at 00:40
  • Yes all methods accessing _class2 can be synchronized then no need to make it volatile. – Rian Rizvi Mar 12 '15 at 00:44
  • thanks...i have edited my question with your suggestions....can you check once ...i think the code should be thread-safe now , right ? – user2912902 Mar 12 '15 at 00:51
  • I see you have this: `public Object synchronized getSomething() { ... _class2.someMethod(); ... }`. Only if getSomething is static will it provide thread safety on _class2. The synchronized keyword when used with a static method, synchronizes access to the class variable, which owns the static variable. A synchronized instance method, as you have written it, only coordinates access to a single instance (via the method). BTW _class2 is not visible from an instance method, you need to qualify it with `MyClass._class2`. Also writing to a static member from an instance method is poor practice. – Rian Rizvi Mar 12 '15 at 06:20
  • variable _class2 is never changed or written outside of the static methods..so when two different threads call getSomething() , they will be reading from the same _class2 variable and hence there shouldn't be any problem of _class2 being in a different state than expected..am i right? – user2912902 Mar 12 '15 at 18:38
  • Yes, if getSomething() at no time changes _class2's state, then no concurrency issues can occur. BTW this is where in say C++ you would declare the method as ... const, to indicate it as such. Unfortunately Java does not have that mechanism. (Do you mind fixing the syntax: `_class2` => `MyClass._class2` within `getSomething()`, and `public Object synchronized getSomething()` => `public synchronized Object getSomething()`? ) – Rian Rizvi Mar 12 '15 at 23:28
  • my bad on switching synchronized with object...fixed it..but i don't need to say MyClass._class2 ..i can access the _class2 variable from getSomething() by just writing _class2 – user2912902 Mar 12 '15 at 23:38
  • 1
    I see, the Java language spec permits you to access a static member from an instance method which is unusual, but anyhow [it is ill-advised](http://stackoverflow.com/questions/610458/why-isnt-calling-a-static-method-by-way-of-an-instance-an-error-for-the-java-co), particularly in your multithreaded situation. Since you now know that instance members have automatic thread protection but static members do not. The clearer notation will help spot issues if they arise. – Rian Rizvi Mar 13 '15 at 00:28
  • i was unaware of this discrepancy in the java language....thanks , i think i got a lot out of this question..... – user2912902 Mar 13 '15 at 00:37
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72888/discussion-between-user2912902-and-riaz-rizvi). – user2912902 Mar 13 '15 at 01:24