0

I am learning synchronized blocks with locks.I want to know the difference between this lock and some third party lock that provided in the program.

public class NewThread extends Thread {
StringBuffer sb;
NewThread(StringBuffer sb){
    this.sb=sb;
}
public void run(){
    synchronized(this.sb){
        for(int i=0;i<1000;i++){
            System.out.print(sb);
               try{
             Thread.sleep(5*60);
        }
        catch(Exception e){}
        }
       char c = this.sb.charAt(0);
       this.sb.setCharAt(0, ++c);
    }
}
public static void main(String[] args){
    StringBuffer sb=new StringBuffer("A");
    NewThread nt=new NewThread(sb);
    NewThread nt1=new NewThread(sb);
    NewThread nt2=new NewThread(sb);
    nt.start();
    nt1.start();
    nt2.start();
}

}

If i am going to put

public void run(){
    synchronized(this){
        for(int i=0;i<1000;i++){
            System.out.print(sb);
               try{
             Thread.sleep(5*60);
        }
        catch(Exception e){}
        }
       char c = this.sb.charAt(0);
       this.sb.setCharAt(0, ++c);
    }
}

here in the above run method i gave this in the synchronized block ...i want the difference between them

i am having one more question ,if we are giving a lock object in synchronized block and we are not using that object inside that block then does we observe any thing specific compared to normal block

satheesh
  • 1,443
  • 7
  • 28
  • 41

3 Answers3

4

If you have concurrent development experience with general OS API, e.g. pthread library in Linux, you may have a knowledge that we should use lock or other data structure to synchronize processes/threads accessing critical section(where shared object may be modified).

Java use lock to implement synchronization block. Synchronization block is a kind of mechanism(called monitor in operating system) encapsulating tedious operation related to lock. Each object has a lock in java. When synchronized, lock in shared object is locked at first(also we can say other process require lock of the shared object). If some thread fail to acquire the lock, that means some other thread is now holding the lock, it must wait until other thread release the lock and re-acquire again until it hold the lock and then enter the critical section.

The first code snippet use lock in instance of StringBuffer, i.e. sb, each thread will try to get sb's lock(invoke lock_of_sb.lock() before running the code. Only that acquired sb's lock successfully can eventually execute the code.

As to the second code, which is equivalent to

public synchronized void run(){
  for(int i=0;i<1000;i++){
      System.out.print(sb);
         try{
       Thread.sleep(5*60);
  }
  catch(Exception e){}
  }
  char c = this.sb.charAt(0);
  this.sb.setCharAt(0, ++c);
}

I don't think it behaves as you expected. It acquire lock in this object, however, this object is never shared. So the shared sb is exposed into the critical section without any synchronization.

The link will give you another working way to achieve synchronization.How to synchronize static method in java Although the question itself is about static method, it also works well to instance member method.

Community
  • 1
  • 1
Summer_More_More_Tea
  • 12,740
  • 12
  • 51
  • 83
  • thanks i understood ..but i didnt get shared locks or sharing of locks ..can u explain that – satheesh Apr 13 '11 at 05:01
  • @satheesh I don't know if this is what you want: in a synchronized multi-thread/process system, generally, only one lock for a kind of resource can exist. It is used to control shared object. In linux, the lock and shared object are separated. While in Java, each object has its own lock(you can find in the source code of class Object). Maybe in linux, we can say a lock is shared by some process because no relation between lock and process/thread. But in Java, since each object has its own lock, no need to share lock explicitly. The lock is maintained implicitly by the object. Feel free to ask. – Summer_More_More_Tea Apr 13 '11 at 05:15
  • ok i understood ..but every thing ur relating with linux and i am little bit confused – satheesh Apr 13 '11 at 05:40
  • @satheesh I'm sorry if my answer confuse you. I write more C code in Linux than Java :-) and he synchronization problem is actually in the scope of operating system. – Summer_More_More_Tea Apr 13 '11 at 05:47
  • great..i am also doing a project in Linux on probe optimisation – satheesh Apr 13 '11 at 05:51
3

Others have already answered but to add my 2 cents,

a) First example is ok, in the sense that the synchronized keyword is guarding the StringBuffer Threads are sharing one lock.

b) Second example is not ok. You are giving each thread a different lock. In effect, it doesn't have any effect (in fact, modern Java compilers remove such locks completely). Locks are meaningful if more than one thread uses it.

You could think of it like this:
If you share a bathroom, you better have one lock for the bathroom (like its door key). If you'd ask everybody to lock their own, individual iPhone before using the bathroom, it would be surely useless. Note that the shared look does not need to be the door key. You might as well as pick one iPhone and use it as the bathroom "key" (everybody has to lock that iPhone before using the bathroom, and only the guy who locked it may unlock it). In real-life that sounds absurd, but that's pretty much what we do with mutexes.

c) The second example can be considered buggy, but in practice, you won't see the effect of the race condition. This is because StringBuffer synchronizes internally. If you use StringBuilder instead, you might be able to see race conditions (depends on runtime conditions).

Enno Shioji
  • 26,542
  • 13
  • 70
  • 109
2

In Java each object can be used as Mutex (See Mutual Exclusion). This means that only one thing can synchronize on an object at any time, which object you use is generally irreverent although it should be as specific as possible. For example if multiple threads are accessing a List, you should synchronized on that list rather than on the entire object (this) so that other things that need something else in the object may access it.

I think the article on mutual exclusion may help to clarify the matter. In essence, only one thread may get the key to a "lock" -- that lock is what is inside synchronized. So long as everything accessing your resource requests the lock on the SAME object, you are protected.

Ben
  • 2,867
  • 2
  • 22
  • 32
  • Satheesh, your examples only differ in the object they lock on. In the first example (this.sb) -- all that means is that only one thread at a time can be inside of a synchronized (this.sb) { } block. Your second example means only one thread can be inside of a synchronized(this) { } block. Which one to use depends - do you want to stop threads from accessing the ENTIRE object at the same time, or just the string buffer? – Ben Apr 13 '11 at 04:46
  • sir..i learn that when synchronized block started then there will be lock on that object that invokes.But here if we are giving this.sb do u meant that more than one threads enters synchronized block and only it cannot access sb object...? – satheesh Apr 13 '11 at 04:56
  • Both work fine. The difference is merely which key you are requiring them to have -- the one to the object, or to the StringBuffer. Thats all synchronized(var) does, requires people to have the key to the "var" lock (of which there is only one) in order to enter the code inside. Once done inside, the key is given to the first thread that gets it. – Ben Apr 13 '11 at 05:00