简体   繁体   中英

java sychronization with object lock confusion

I have read many tutorials about Java object level synchronization. And what I understand is whenever a thread is call a synchronized method/block it will acquire a lock on the method's object and release after the execution. So no other threads can access the same object data while it is in lock. But when I tried the below scenario, found that other thread can access non-synchronized method of a locked object parallel.

class A {
    public synchronized void test1(){}
    public void test2(){}
}  

I created 3 threads t1 , t2 and t3 . And all are referring the same object of class A. t1 is calling test1() and other two threads calling test2() . Here I can see that while test1() is executing, t2 and t3 threads test2() also running in parallel.

So my question is does the synchronization really locks an object completely or it just lock only the particular synchronized method? If so why it is calling as object level locking.

What will happen in the case of class level locking?

Synchronization ensures that any thread that needs to execute a block of code in a synchronized block will first have to get the Object's monitor ( lock ) before the execution of code inside the block starts. Thus when one thread is executing code inside a synchronized block, other threads that try to execute the same or other synchronized blocks (on the same object ie same lock ) will have to wait until they get the lock.

Other threads are allowed to execute code in code blocks that are not synchronized because that doesn't involve acquiring the monitor / lock. Note that other threads can even execute code that is in synchronized blocks if they need to acquire a different lock.

Other threads will need to acquire lock if they try to execute any other method which is synchronised. They are free to call other method which do not have synchronised keyword (even if the lock is aquired by some thread) as to call them they do not need to aquire lock / moniter.

There's a different between explicitly locking to an object (eg an instance of A ), and the intrinsic locking idioms declared in your A class.

In your case, method test1 is instance-synchronized, which means that for a given instance of A , only one thread at the time can invoke it.

However, test2 is not synchronized, therefore any thread at any given time can invoke it in theory.

Now if you synchronized(myAInstance) , then once the lock is acquired, only the executing code within the synchronized statement will be able to invoke any method of your A instance, until the lock is released.

You are really mixing up things.

class A {
  public synchronized void test1(){}
  public void test2(){}
}  

This creates a synchronized access to your test1 method. This means, that only one thread in parallel could execute that method. If you want to have a lock accross methods you could create your own lock object:

class A {
   private static final Object myLock= new Object();

   public void test1(){
      synchronized (myLock){

      }
   }
   public void test2(){
      synchronized (myLock){

      }
   }
}  

If any other person in your application uses the same object, your thread is blocked, too. Normally you define some kind of lock object structure that everybody follows.

While thinking of synchronization as a means for exclusion might be appropriate in many cases, there is another way to think of it that might be more illustrative for others, and that is the idea of visibility .

Exiting a synchronized block means that all of your changes are committed back to memory. Entering a synchronized block guarantees that all changes anyone else might have done to the memory you are about to access are properly visible to you.

If you think of synchronization as a way to lock others out while you are doing your stuff, you need to think of it as an "occupied"-note rather than a door lock: it is only by the others courtesy you can be alone - that is, if they, too, are using the same synchronization mechanism. Thinking about visibility makes it easier to grasp why it pays off to be courteous.

In your case, of course, both the test1 and the test2 methods have to me marked 'synchronized'. This is the same as using the A-object as a lock.

Going further, I would really like to encourage you to have a look at the java.util.concurrent -package and its subpackages atomic and locks . Most of the things you want to achieve is already implemented there, and using the libraries makes things easier and safer for you. It also makes your code more maintainable and easier to read.

Read oracle documentation page on synchrnoized methods

Making these methods synchronized has two effects:

First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

=> At any point of time, you can't execute two synchronized methods on same object in parallel.

Coming back to your query:

test1() is synchronized and test2() is not.

T1 execution of test1() and T2 & T3 exection of test2() does not break above rule and hence they can run in parallel.

If you change test2() to synchronized method, things will change.

In this case, till T1 completes it's execution of test1() , T2 and T3 have to wait till T1 completes it's execution. Once T1 completes its execution, then one of T2 or T3 can invoke test2() method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM