views:

84

answers:

4

Hi. I have a class like this:

public class Utils {

    public static void doSomething() {
        // doSomething code
    }

    public static void doSomethingElse() {
        // doSomethingElse code
    }
}

I want the two methods to be synchronized but not synchronized against each other i.e. no two threads can process the doSomething() method at the same time, no two threads can process doSomethingElse() at the same time but it is OK for a thread to process the doSomething() method and another to process the doSomethingElse() method at the same time.

I've implemented something like this:

public class Utils {

    private static final String DO_SOMETHING_LOCK = "DO_SOMETHING_LOCK";
    private static final String DO_SOMETHING_ELSE_LOCK = "DO_SOMETHING_ELSE_LOCK";

    public static void doSomething() {
        synchronized(DO_SOMETHING_LOCK) {
            // doSomething code
        }
    }

    public static void doSomethingElse() {
        synchronized(DO_SOMETHING_ELSE_LOCK) {
        // doSomethingElse code
    }
}

I see the Scott Stanchfield response uses a similar approach here:

http://stackoverflow.com/questions/578904/how-do-synchronized-static-methods-work-in-java

but is this the best way to do this? It seems kind of clunky to me, creating two objects, only to be used for locking - is there a better way to do this?

+1  A: 

Yes that's the easiest way. Although, the object that you lock on doesn't have to be anything special. You could just make them Integers with no values set.

Dave
A: 

Your solution seems correct. I usually see/use Object's instances as locks (instead of Strings), like:

public class Utils {

    private static final Object[] lock = new Object[] { new Object(), new Object() };

    public static void doSomething() {
        synchronized(lock[0]) {
            // doSomething code
        }
    }
    ...
}

The problem you're trying to solve is related to ThreadLocal class use cases.

Roman
Why the array???
Tom Hawtin - tackline
this is actually worse than the author's version as one does not know what lock[0] is supposed to protect - it has no name. The only useful point is to use new Object() and not a "STRING"
unbeli
@Tom Hawtin - tackline: what's wrong with array? My answer may be wrong but your comment points nothing. Downvote you until better explanation appears.
Roman
What's wrong with the array?? It doesn't make any sense!! / So you've downvoted me for commenting on your answer?
Tom Hawtin - tackline
@Roman I explained you what's wrong with the array, don't be silly
unbeli
@Tom Hawtin - tackline, unbeli: so, the reason for 2 downvotes is that `lock[0]` doesn't have its own name and that's all?
Roman
@Roman yes. Anyone can write code that works. One must learn how to write code that is easy to read.
unbeli
@Roman How would I know? Why are you asking me?
Tom Hawtin - tackline
I have to agree that using the array is a bad idea. Now doSomething's lock is tied to offset 0 of the array. "0" is quite meaning less when reading the code. And what happens if the array is changed, lock[0] = new String("something else"), now it's even more broken.
Steve Kuo
+1  A: 

Locking on interned Strings is a mistake. If you run FindBugs, I believe it will point this out for you. Create a new instance of an object for the lock - new Object() or new String("Something informative"). To see something useful in stack traces when it dead locks, use a custom class for the job.

private final Object lock = new Object() { };

or

private static final class MyLock { }
private final Object lock = new MyLock();

In fact, it is generally better to create a private internal object (objects are really small - do the maths) than expose the lock through a public interface.

Tom Hawtin - tackline
+4  A: 

Using strings is not a good idea, because the same string might appear somewhere else, it will be the same object and you can get dependencies where you don't what them. Just do

private static final Object DO_SOMETHING_LOCK = new Object();

The rest is ok.

unbeli
Question asker here.The String value is related to the method name that I'm synchronizing so it won't appear elsewhere but I take your point, I'll use Objects instead.I know my solution works by the way, I'm not asking if it works but if there is a more elegant solution that doesn't involve creating objects solely for the purpose of locking?
dairemac
Creating objects for locking is ok. After all, this is the only thing you can lock on in Java, so you either create it or find a suitable existing object.
unbeli
Creating lock objects is a very common solution.
matt b
@dairemac: While `String` may be safe for static methods, you'll eventually get burned using String objects for synchronizing because Strings are interned; there is only one copy of a given `String`.
R. Bemrose
@R. Bemrose it's not about String as a class, but about string constants. You can safely use new String("whatever") if you like.
unbeli
I think `byte[] b = new byte[0]` has a smaller memory footprint
Bozho