views:

736

answers:

5

What is the significance of parameter passed to synchronized?

synchronized ( parameter )
{

}

to achieve block level synchronization. Somewhere i saw code like

class test
{
    public static final int lock =1;

    ...

    synchronized(lock){
       ...
    }
}

I don't understand the purpose of this code.

Can anyone give me a better example and/or explain it?

+4  A: 

This:

public synchronized void blah() {
  // do stuff
}

is semantically equivalent to:

public void blah() {
  synchronized (this) {
    // do stuff
  }
}

Some people don't like to use 'this' for synchronization, partly because it's public (in that the instance is visible to external code). That's why you end up with people using private locks:

public class Foo
  private final static String LOCK = new String("LOCK");

  public void blah() {
    synchronized (LOCK) {
      // do stuff
    }
  }
}

The benefit is that LOCK is not visible outside the class plus you can create several locks to deal with more fine-grained locking situations.

cletus
+1  A: 

The purpose of the synchronized statement (ref: here) is to make sure that in a multi-threaded application, only one thread can access a critical data structure at a given time.

For instance, if you let two threads change the same data structure at the same time, the data structure would be corrupted, then you typically protect it with a lock.

In the real world, consider an analog where a public toilet has a key, hanging in a central place. Before you can use the toilet, you need the key, not only to enter, but it's also a guarantee that nobody else will try to enter the same toilet at the same time. They'll have to wait for the key to become available.

This is how such a lock construct works.

The parameter to the synchronized keyword is the key in this case. You lock the key, do what you need to do, then you unlock the key to let others have access to it. If other threads tries to lock the key while it is currently being locked by another thread, that thread will have to wait.

Lasse V. Karlsen
+1  A: 

The object instance that is passed in to synchronized is the "unit of locking". Other threads that execute that try to gain a lock on the same instance will all wait their turn.

The reason people use this rather than the method level synchronized keyword (which locks on the executing class object's instance) is that they might want a finer-grained or different thing to wait for locking on, depending on how their multi-threaded algorithm is designed.

Macker
+7  A: 

It's the reference to lock on. Basically two threads won't execute blocks of code synchronized using the same reference at the same time. As Cletus says, a synchronized method is mostly equivalent to using synchronized (this) inside the method.

I very much hope that the example code you saw wasn't quite like that - you're trying to synchronize on a primitive variable. Synchronization only works on a monitor (via a reference) - even if it were legal code, x would be boxed, which would lead to some very odd behaviour, as some integers will always be boxed to the same references, and others will create a new object each time you box. Fortunately, the Java compiler realises this is a very bad idea, and will give you a compile-time error for the code you've posted.

More reasonable code is:

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

    ...

    synchronized(lock){
       ...
    }
}

I've made the lock private, and changes its type to Object. Whether or not it should be static depends on the situation - basically a static variable is usually used if you want to access/change static data from multiple threads; instance variables are usually used for locks when you want to access/change per-instance data from multiple threads.

Jon Skeet
That's true - will edit. (Static may well be okay, depending on the context.)
Jon Skeet
public and static lock also isn't good idea :-) Btw, in Java, integer 1 is always boxed to the very same object.
Peter Štibraný
Peter: Indeed - hence the "some integers" bit. However, it would be very odd to see the behaviour change based on a change from 127 to 128. (I mistakenly thought it was valid but unfortunate code - but it turns out I was compiling the wrong file. Oops.)
Jon Skeet
True. I was also wondering if that was even legal code, but it turned out that it isn's possible.
Peter Štibraný
+2  A: 

I can't explain it as it doesn't compile. You cannot lock a primitive.

Another bad example would be to change it to

public static final Integer lock =1;

This is a bad idea as small auto-boxed primitives are cached and is likely to have strange side effects (if this is done more than once)

Peter Lawrey