views:

224

answers:

4

What could be the understanding of the following?
I have gone through this post at SO but still at a loss to assemble it.

code1:

synchronized(this){ 
// some code
}

code2:

Object lock = new Object();

synchronized(lock){
// some code
}

Any tutorial, or some links to explain synchronized like they explain it to a child?

+5  A: 

Basically there is a "lock" associated with every object in Java.

When a thread reaches a call to synchronized(something), it has to acquire the lock of something before continuing. If you want to allow only one thread at a time to modify the state of an object, the most obvious thing is to synchronize on the lock of that object. If different methods are allowed to be called in parallel, you need different locks for that.

If you write synchronized(this), or simply synchronized, the thread must acquire the lock associated with the current object (of which method is called).

Note that since Java 5.0 there concurrent package provides proper locks which can be used instead of synchronization.

Zed
Could you provide some examples or some links to further my understanding on the topic, thanks!
Kevin Boyd
Have you read this? http://java.sun.com/docs/books/tutorial/essential/concurrency
Zed
I will, Now!, thanks!
Kevin Boyd
+2  A: 

Putting code within a synchronized block essentially means, "Once this code starts running, other code that needs to use this object cannot run at the same time."

So, if Thread #2 is executing code in your code2 block, when it comes to the synchronized(lock) code it has to effectively look around at all the other threads to make sure nobody else is running "synchronized" code with the lock object at the moment. Thread #1 is certainly running some code at the same time, but it might be completely unrelated code. If so, it's safe for Thread #2 to start running your "some code" stuff.

Meanwhile, if Thread #1 gets to the synchronized(this) block, it too has to pause and see if any other threads are using this. If this is the same object as lock, we have a problem. We were told that only one thread can possibly use that object (in a synchronized block) at the same time. Yet Thread #2 is already using it. Thread #1 will just have to wait... and wait... and wait... until eventually Thread #2 finishes. Then we can proceed.

The end result is that only one synchronized block can run at a time (with a particular object, of course).

VoteyDisciple
Well explained!
Kevin Boyd
+2  A: 

Suppose you have an Account object which has a method:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException
{
   if (accountBalance >= debitAmount) {
      accountBalance -= debitAmount;
      beneficiary.credit(debitAmount);
   }
   else {
      throw new InsufficientFundsException();
   }
}

Now suppose you have an account with a balance of 100 euros, and you get two attempts to debit it by 70 euros. If the two debits occur at the same time, you can get a race condition like this:

  • First debit checks account balance: 100 >= 70, so succeeds
  • Second debit checks account balance: 100 >= 70, so succeeds
  • First debit executes; account balance becomes 30
  • Second debit executes; account balance becomes -40. Shouldn't be allowed

We can prevent this dire state of affairs by synchronizing on the Account object's lock:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException
{
   synchronized (this) {
      if (accountBalance >= debitAmount) {
         accountBalance -= debitAmount;
         beneficiary.credit(debitAmount);
      }
      else {
         throw new InsufficientFundsException();
      }
   }
}

This makes sure that the test on the account balance and the debit can't be interrupted by another test on the account balance.

The Sun Java tutorial is a good place to start for information on concurrency and locking.

Simon Nickerson
+2  A: 

One thing not mentioned in the otherwise excellent answers already given is that difference between code1 and code2. In code1, the synchronization is on the instance of the object in which the code is found, and in code2, it's on the specific lock object within the object.

If there's only the two synchronized blocks in the enclosing class, there's no functional difference between the two, but consider this:

class CodeOneClass {
  ...
  synchronized(this) {   // or merely "synchronized" - it defaults to this
      first protected code block
  }
  ...
  synchronized(this) {   
      second protected code block
  }
...
}

class CodeTwoClass {
  ...
  Object lock1 = new Object();
  synchronized(lock1) {   
      first protected code block
  }
  ...
  Object lock2 = new Object();
  synchronized(lock2) {   
      second protected code block
  }
...
}

If two threads are trying to use the same instance of CodeOneClass, only one of them can be in either of the two protected code blocks at the same time.

But with the second idiom, you have the flexibility to say that it's safe for one thread to be in the first protected block, and another to be in the other. Note that if the locks were the same (both synchronizing on the same lock object), the behavior would be as the first.

There are other differences. Some writers are beginning to point out issues with synchronized(this) - I would point you to another post here on SO: http://stackoverflow.com/questions/442564/avoid-synchronizedthis-in-java

I highly recommend reading it, and the three posts it links to.

CPerkins
Other answers are also excellent? Wish I had an option to check mark more right/ useful answers?
Kevin Boyd