views:

63

answers:

5

I often find myself with code like

private static final MyType sharedResource = MyType();
private static final Object lock = new Object();
...
synchronized(lock)
{
    //do stuff with sharedResource
}

Is this really neccessary or could sharedResource be used as the lock itself like

private static final MyType sharedResource = MyType();
...
synchronized(sharedResource)
{
    //do stuff with sharedResource
}

Note: synchronized blocks shown in the examples would live within methods doing work and are not methods themselves or synchronized methods.

EDIT: A very good point has been pointed out in some of the answers that if we are dealing with multiple shared resources that the first "Object" technique is far safer.

WARNING The fact that sharedResource is static is important! If it is static then synchronized methods or synchronized blocks locking on this won't work. The lock object must also be static.

A: 

Yes, you can absolutely do that.

In fact it improves clarity and reduces clutter.

Drew Wills
+1  A: 

The only problem I see, with using sharedResource as a lock if MyType has methods defined as synchronized itself. In this case, some strange behaviour my occur that was not intended by the developers of MyType. (See glowcoder's comment for an example.)

Otherwise it should be fine, however if you do only need one lock anyway, then just synchronize on this instead of introducing an additional dummy object.

Btw, did you itentionally make your lock object static? Because this means that all instance lock on the same monitor, i.e. they can block each other, which may not bee the behaviour you intended.

inflagranti
Good point here about synchronized methods. But if the resource itself is designed to be thread-safe, it seems less likely you'd need/want to create a synchronized block for it.
Drew Wills
could you clarify this a bit? I wasn't aware there was in issue in multiple layers of synchronization blocks. For instance I would think that if a thread entered a MyType function it would already have the "this" instance in its posession so it could proceed into the synch block.
Adam
What I was thinking of is a `MyType` that makes certain assumptions about locking behaviour and if those assumptions are broken, because a client of the class locks on the same monitor, race conditions could occur.
inflagranti
Adam, a multiple layer of synch issue would be imagine a developer knows to synch on A B and C... and does `synch(A) { synch(B) { synch(C) { foo(A,B,C); } } }`... and another dev knows to synch on them but mixes the order up `synch(C) { synch(B) { synch(A) { foo{A,B,C); } } }` Now, if both threads execute, thread 1 synchs on A and B, then a context switch occurs, thread 2 synchs on C, then waits on B (held by 1), then a context switch to thread 1 waits on C (held by 2)... and voila! A deadlock caused by layers of synch. *breathes*
glowcoder
Thanks for the great example glowcoder. I had an intuitive feeling that there must be some kind of problem that could appear, but couldnt formulate it :)
inflagranti
@glowcoder Thanks glowcoder. I completely agree that nesting like that is looking for big time trouble and would use a single Object lock for multiple resources.
Adam
@inflagranti `this` will not work for the same reason I intentionally make the lock static. The lock should be of the same scope as the resource it is protecting. If `this` is used then each instance of the object can access the static variable regardless of other instance's locks.
Adam
@Adam: Ok, I see. The problem with synchronized methods in MyType still apply though.
inflagranti
A: 

If I remembered right, synchronized is a monitor, it grants that only one thread can access that object at any given time in the same JVM. So I think you are only accessing shardResouce, synchronizing on the shardResouce is sufficient.

Viele
What if different threads need to access distinct areas of the object? Should one be blocked while the other does something unrelated?
glowcoder
The synchronized keyword allow only one thread to access the object that is the following brackets. Anything thread attempting to access that object, should use synchronized as well, or they would be breaking the protocol, wouldn't they?
Viele
+1  A: 

Pros and cons of both

First option pros: Allows locking on concept, not on Objects. If you had to lock on multiple resources for a single action (which is usually not advised, but sometimes necessary) you could do this with much less worry about race conditions.

cons: The object could still be modified, so you need to ensure access to the object is restricted to methods that abide by the external lock.

Second option pros: Lock on the object should prevent others from modifying it (although you should double check the exact symantics.) EDIT: Has the same con as above - if the methods aren't synchronized internally, you could still run into methods that don't abide by the contract.

cons: You block access to all methods, even those unrelated to what you're trying to operate, which could cause slowdowns and possibly deadlock. You could easily make the case, however, that if that's the case your Object is doing too much work and should be broken up.

EDIT: Allow me to clarify part 2 here (the case to break up MyType into MyFoo and MyBar is open for debate...)

class MyType {
   Foo foo;
   Bar bar;

   void doFoo() { foo.do(); }
   void doBar() { bar.do(); }
}

class MyActions {
    MyType thing;

    void lotsOfFoo() {
        // blocks bar :-(
        synchronized(thing) { thing.doFoo(); } 
    }

    void lotsOfBar() {
        // blocks foo :-(
        synchronized(thing) { thing.doBar(); } 
    }

}

Personally, I use option 1 much more often (that's why I'm unsure about that part in option 2).

glowcoder
I hadn't realized that using an object as a lock keeps other threads from using the methods on the object! That makes a big difference. Can you site any place that confirms this?
Adam
Look up what `synchronize` does. Especially, what the definition `synchronize void method()` means; namely, that `method` is synchronized on the `this`-object. If you now explicitly synchronize on `this` or on a variable that references that object, you are going to block each other.
inflagranti
I will clarify part 2 some more.
glowcoder
I don't think we are talking about synchronized methods here, so I'm not sure what that has to do with anything.
Adam
A: 

Personally, I don't usually synchronize on an arbitrary lock. That is, I'd usually do something along the lines of your second approach:

private static final MyType sharedResource = MyType();
...
synchronized(sharedResource) {
    //do stuff with sharedResource
}

Of course, before running synchronized code, the lock for the target object must be obtained. Often, I take the locking "down" a step further, so to speak. Meaning, I would synchronize on a method within "sharedResource." As in:

public class MyType {

    public void synchronized doWork() {

    }
}

But when it comes to this kind of thing, it's hard to make generalizations because there are exceptions to every rule. In the end, your overall architecture requirements will dictate where your locking should occur. For me, most often, I find myself synchronizing the top-level method that accesses the shared resources and it is thereby more rare to lock on an object who does nothing more than serve as a lock.

EDIT: minor grammar fixes

gmale
-1 WARNING: Synchronizing on a method is different than synchronizing on a static instance. This is because synchronizing on a method blocks on this instance of the class instead of across all instances.
Adam
Sheesh -1 is pretty harsh. lol. It's pretty easy to miss the word static in your first message, which originally didn't mention that as a major consideration. In hindsight, it's clear that by "shared resource" you meant "static resource" but it wasn't immediately obvious in your question. To me "shared" referred to something shared among threads.
gmale
It's plainly clear that several other responses didn't notice we were discussing a static object, either. ;)
gmale
@Adam: Why is that the case? You're still calling instance methods on the object. There's only one instance that your class deals with if your reference to it is static. But it should not matter whether you synchronize outside of the class or inside, since you are still only dealing with one object on which to synchronize.
Platinum Azure
@Adam: lastly, your criticism is incorrect. :) There is only one instance of a Static Object on the JVM. Synchronized static methods use the monitor of the class object as a lock. So, functionally, it's the same as using a "dummy lock" *(as in synchronized(MyType.class){ //code })*. Thereby, synchronizing methods within the static object itself, as I stated, is a valid approach since it would, "block across all instances." :)
gmale
I agree that the -1 was harsh after seeing others miss the static too, but I can't remove it until the answer is edited. Let me clarify my comment: Synchronizing on a the method that *uses* `sharedResource` will not work because there may be many instances of that class. I agree there will only be one instance of `sharedResource`.
Adam
@gmale if you edit your answer in some way then I can remove my downvote. It's just locked in.
Adam