开发者

Java class level lock vs. object level lock

If a thread T1 enters a method m1 by obtaining the class level lock, does this mean another thread T2 cannot run a different method m2 by obtaining the object level lo开发者_如何学运维ck?


No, it doesn't mean that. The "class level lock" is just a regular lock on a different object, namely SomeClass.class. The "object level lock" locks on this.

Edit: Just to make sure I'm following your understanding of the terminology, you're wondering if m1 and m2 can be run concurrently as they are defined below:

public class SomeClass {
    public synchronized static void m1() {
       //do something
    }

    public synchronized void m2() {
       //do something
    }
}

And the answer is yes, m1 and m2 can be run concurrently. It is functionally equivalent to this:

public class SomeClass {
    public static void m1() {
        synchronized (SomeClass.class) {
           //do something
        }
    }
    public void m2() {
        synchronized (this) {
           //do something
        }
    }
}

Since they are synchronizing on completely different objects, they are not mutually exclusive.


Object level locking:

Object level locking is mechanism when you want to synchronize a non-static method or non-static code block such that only one thread will be able to execute the code block on given instance of the class. This should always be done to make instance level data thread safe. This can be done as below :

public class DemoClass 
{ 
  public synchronized void demoMethod(){} 
} 

or 

public class DemoClass 
{ 
  public void demoMethod(){ 
  synchronized (this) 
  { 
   //other thread safe code 
  } 
 } 
} 

or 

public class DemoClass 
{ 
  private final Object lock = new Object(); 
  public void demoMethod(){ 
  synchronized (lock) 
 { 
  //other thread safe code 
 } 
} 

Class level locking:

Class level locking prevents multiple threads to enter in synchronized block in any of all available instances on runtime. This means if in runtime there are 100 instances of DemoClass, then only one thread will be able to execute demoMethod() in any one of instance at a time, and all other instances will be locked for other threads. This should always be done to make static data thread safe.

public class DemoClass 
{ 
  public synchronized static void demoMethod(){} 
} 

or 

public class DemoClass 
{ 
  public void demoMethod(){ 
  synchronized (DemoClass.class) 
  { 
   //other thread safe code 
  } 
 } 
} 

or 

public class DemoClass 
{ 
 private final static Object lock = new Object(); 
 public void demoMethod(){ 
 synchronized (lock) 
  { 
   //other thread safe code 
  } 
 } 
}


Example to understand Object and Class level locks in Java

1) Object Level lock example

package com.test;

public class Foo implements Runnable {

    @Override
    public void run() {
        Lock();
    }
    public void Lock() {
        System.out.println(Thread.currentThread().getName());
        synchronized(this) {
            System.out.println("in block " + Thread.currentThread().getName());
            System.out.println("in block " + Thread.currentThread().getName() + " end");
        }
    }

    public static void main(String[] args) {
        Foo b1 = new Foo();
        Thread t1 = new Thread(b1);
        Thread t2 = new Thread(b1);             
        Foo b2 = new Foo();
        Thread t3 = new Thread(b2);             
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");             
        t1.start();
        t2.start();
        t3.start();
    }
}

output:

    t1
    t3
    t2
    in block t3
    in block t1
    in block t3 end
    in block t1 end
    in block t2

Note that t3 will not block when threads t1 and t2 block. Because the lock is placed on this object and thread t3 has different this object than thread t1,t2

2) Class Level lock example

The code in object level lock, only Foo.class is added in synchronized block. All the threads are getting created using object of Foo class will get blocked.

package com.test;    
public class Foo implements Runnable {        
    @Override
    public void run() {
        Lock();
    }

    public void Lock() {
        System.out.println(Thread.currentThread().getName());
        synchronized(Foo.class) {
            System.out.println("in block " + Thread.currentThread().getName());
            System.out.println("in block " + Thread.currentThread().getName() + " end");
        }
    }

    public static void main(String[] args) {
        Foo b1 = new Foo();
        Thread t1 = new Thread(b1);
        Thread t2 = new Thread(b1);             
        Foo b2 = new Foo();
        Thread t3 = new Thread(b2);             
        t1.setName("t1");
        t2.setName("t2");
        t3.setName("t3");             
        t1.start();
        t2.start();
        t3.start();
    }
}

output:

t1
t3
in block t1
in block t1 end
t2
in block t3
in block t3 end
in block t2
in block t2 end

Synchronized block is going to be executed for the same thread.


If a thread T1 enters a method m1 by obtaining the class level lock, does this mean another thread T2 cannot run a different method m2 by obtaining the object level lock?

Object level lock and Class level locks are different. In above case, T2 can run method m2 by obtaining object level lock. But if m2 is static synchronized, T2 can't invoke m2 method unless T1 release class level lock on method m1.

Object level lock:

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.

Assume that you have two synchronized methods m1 and m2 on Object O. If Thread T1 is in middle of execution of method m1, then Thread T2 has to wait to call method m2 on same object O unless Thread T1 release lock on method m1.

Class level lock:

Thread acquires the intrinsic lock for the Class object associated with the class. Thus access to class's static fields is controlled by a lock that's distinct from the lock for any instance of the class.

Assume that method m1 is static synchronized and method m2 is also static synchronized and you have two different objects o1 and o2.

If Thread T1 is in middle of execution of method m1 on object o1, then Thread T2 has to wait to call method m2 on object o2 unless Thread T1 release lock on method m1.


In java there are two types of locks:

  1. Class Level
  2. Object Level

In case of Static methods the lock is always checked on class but in case of instance methods the lock is always checked on object.

Example:

show1() is non static and show() is static. Now, show() is called by class name (or by object) and show1() is called by object, then both methods can accessed simultaneously by two threads.

class Shared{
    static int x;
    static synchronized void show(String s,int a){
        x=a;
        System.out.println("Starting in method "+s+" "+x);
        try{
            Thread.sleep(2000);
        }
        catch(Exception e){ }
        System.out.println("Ending from method "+s+" "+x);
    }
    synchronized void show1(String s,int a){
        x=a;
        System.out.println("Starting show1 "+s);
        try{
            Thread.sleep(2000);
        }
        catch(Exception e){ }
        System.out.println("Ending from show1 "+s);
    }
}
class CustomThread extends Thread{
    Shared s;
    public CustomThread(Shared s,String str){
        super(str);
        this.s=s;
        start();
    }
    public void run(){
        Shared.show(Thread.currentThread().getName(),10);
    }
}
class CustomThread1 extends Thread{
    Shared s;
    public CustomThread1(Shared s,String str){
        super(str);
        this.s=s;
        start();
    }
    public void run(){
        s.show1(Thread.currentThread().getName(),20);
    }
}
public class RunSync {
    public static void main(String[] args) {
        Shared sh=new Shared();
        CustomThread t1=new CustomThread(sh,"one");
        CustomThread1 t2=new CustomThread1(sh,"two");
    }
}

Output:

Starting in method one 10
Starting show1 two
Ending from method one 20
Ending from show1 two        


Nope, both can execute concurrently. 1.When class level lock is applied on one method synchronized(SomeClass.class) and on other method object level lock is applied synchronized(this) then, both can execute at same time.

only when class level lock is applied on both methods then there is no concurrent execution.

Reason being: for class, jvm creates object for java.lang.Class, i.e. in short everything in java is object. So, when class level lock is applied on 2 methods, common lock is applied on class object and every object has single lock so, every thread waits, but when different instance is used to invoke the 2nd method and instance level lock is applied at that time, this object lock is applied which is different from class object lock and so concurrent execution is possible.


Class level lock is achieved by keyword "Static Synchronized,where as object level is achieved only by synchronized keyword. Object level lock is achieved to restrict same object to operate through different thread,where as class level lock is achieved to restrict any object to operate.


Class level lock and instance level lock both are different. Both don’t interfere each other lock status. If one instance of a class has already got locked by a thread then another thread can’t get lock for that instance until unless lock is freed by first thread. Same behaviour is there for class level lock.

But if a thread acquires Class level lock then another thread can acquire lock on one of its instance. Both can work parallel.`

package lock;

class LockA implements Runnable {
    @Override
    public void run() {
        synchronized (LockA.class) {
            System.out.println("Class");
            try {
                Thread.sleep(60 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestClassVsInstanceLock {
    public static void main(String[] args) {
        final LockA a = new LockA();
        final LockA b = new LockA();
        try {
            Thread t = new Thread(a);
            Thread t1 = new Thread() {
                @Override
                public void run() {
                    synchronized (b) {
                        System.out.println("Instance 1"+ currentThread().currentThread().holdsLock(b));
                        try {
                            Thread.sleep(10 * 1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            t.start();
            t1.start();
            synchronized (a) {
                System.out.println("Instance2");
                Thread.sleep(10 * 1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

`

This will print : - Instance2 Class Instance 1true

All will get printed instantly without any pause.


Different ways of class level locking: 1) public class DemoClass {

public static synchronized void demoMethod(){
    //dosomething
}

}

2)

public class DemoClass {

public void demoMethod(){

    synchronized(DemoClass.class){
        //dosomething
    } 
}

}

3)

public class DemoClass {

private final static Object lock = new Object(); 
public void demoMethod(){

    synchronized(lock){
        //dosomething
    } 
}

}


It’s possible that both static synchronized and non static synchronized method can run simultaneously or concurrently because they lock on different object.

Courtesy


Instance Level Locking, Only single thread is allowed to execute at a time using instance level locking.

 public class Refactor implements Runnable {
        private Object obj;

        public Refactor(Object obj)
        {
            this.obj = obj;
        }

        public void run() {

            if (Thread.currentThread().getName().equalsIgnoreCase("Test1")) {
                test1();
            } else {
                test2();
            }

        }

        public void test1() {
            synchronized (obj) {
                System.out.println("Test1");
            }
        }

        public synchronized void test2() {
            synchronized (obj) {
                System.out.println("Test2");
            }
        }

        public static void main(String[] args) {
            Object obj = new Object();
            Thread t1 = new Thread(new Refactor(obj));
            t1.setName("Test1");
            t1.start();
            Thread t2 = new Thread(new Refactor(obj));
            t2.setName("Test2");
            t2.start();
        }

    }

Class Level Locking, Only single thread is allowed to execute at a time using class level locking.

public class Refactor implements Runnable {
    private Object obj;

    public Refactor(Object obj)
    {
        this.obj = obj;
    }

    public void run() {

        if (Thread.currentThread().getName().equalsIgnoreCase("Test1")) {
            test1();
        } else {
            test2();
        }

    }

    public static void test1() {
        synchronized (Refactor.class) {
            System.out.println("Test1");
        }
    }

    public static synchronized void test2() {
        synchronized (Refactor.class) {
            System.out.println("Test2");
        }
    }

    public static void main(String[] args) {
        Object obj = new Object();
        Thread t1 = new Thread(new Refactor(obj));
        t1.setName("Test1");
        t1.start();
        Thread t2 = new Thread(new Refactor(obj));
        t2.setName("Test2");
        t2.start();
    }

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜