Java类级别锁定与对象级别锁定

kgi*_*kgi 21 java multithreading locking

如果线程T1通过获取类级别锁定进入方法m1,这是否意味着另一个线程T2无法通过获取对象级别锁定来运行不同的方法m2?

Mar*_*ers 46

不,这并不意味着."类级别锁定"只是对不同对象的常规锁定,即SomeClass.class."对象级锁定"锁定this.

编辑:为了确保我遵循您对术语的理解,您想知道m1和m2是否可以同时运行,因为它们定义如下:

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

    public synchronized void m2() {
       //do something
    }
}
Run Code Online (Sandbox Code Playgroud)

答案是肯定的,m1和m2可以同时运行.它在功能上等同于:

public class SomeClass {
    public static void m1() {
        synchronized (SomeClass.class) {
           //do something
        }
    }
    public void m2() {
        synchronized (this) {
           //do something
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

由于它们在完全不同的对象上同步,因此它们不是互斥的.

  • @ buch11:这是正确的,就好像它们都在执行`synchronized(SomeClass.class){...}`,并禁止任何复杂的类加载方案,这两种情况下都是相同的对象.从技术上讲,类加载允许您具有相同类的两个单独的"加载",并且可以并行地在这些不同的类中运行静态同步方法.但除非这种愚蠢,否则它是相互排斥的. (3认同)
  • 如果这两个方法都声明为静态怎么办?我相信在那种情况下,两者会相互排斥,对吗? (2认同)

Sne*_*sne 19

对象级锁定:

当您想要同步非静态方法或非静态代码块时,对象级锁定是一种机制,这样只有一个线程能够在给定的类实例上执行代码块.应始终这样做以使实例级数据线程安全.这可以通过以下方式完成:

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 
 } 
} 
Run Code Online (Sandbox Code Playgroud)

类级别锁定:

类级别锁定可防止多个线程在运行时的所有可用实例中的同步块中输入.这意味着如果在运行时有100个DemoClass实例,那么一次只有一个线程可以在任何一个实例中执行demoMethod(),并且其他所有实例都将被锁定用于其他线程.应始终这样做以使静态数据线程安全.

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 
  } 
 } 
}
Run Code Online (Sandbox Code Playgroud)


小智 6

在java中有两种类型的锁:

  1. 班级
  2. 对象级别

在静态方法的情况下,始终在类上检查锁,但是在实例方法的情况下,始终在对象上检查锁.

例:

show1()就是非静态的show()静态的.现在,show()由类名(或对象) show1()调用并由对象调用,然后两个方法可以同时访问这两个方法.

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Starting in method one 10
Starting show1 two
Ending from method one 20
Ending from show1 two        
Run Code Online (Sandbox Code Playgroud)


小智 6

理解Java中的对象和类级别锁的示例

1)对象级别锁定示例

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

    t1
    t3
    t2
    in block t3
    in block t1
    in block t3 end
    in block t1 end
    in block t2
Run Code Online (Sandbox Code Playgroud)

请注意,当线程t1和t2阻塞时,t3不会阻塞。因为锁位于此对象上,并且线程t3与线程t1,t2 具有不同的对象

2)类级别锁定示例

对象级锁定中的代码,仅Foo.class被添加到同步块中。使用Foo类的对象创建的所有线程都将被阻塞。

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

t1
t3
in block t1
in block t1 end
t2
in block t3
in block t3 end
in block t2
in block t2 end
Run Code Online (Sandbox Code Playgroud)

同步块将针对同一线程执行。


Rav*_*abu 6

如果线程T1通过获取类级别锁进入方法m1,这是否意味着另一个线程T2无法通过获取对象级别锁来运行其他方法m2?

对象级别锁和类级别锁不同。在上述情况下,T2可以通过获取对象级别锁定来运行方法m2。但是,如果m2为static synchronized,则T2不能调用m2方法,除非T1释放方法m1上的类级别锁定。

对象级别锁定

synchronized同一对象上的两次方法调用不可能交织。当一个线程正在执行synchronized对象的方法时,所有其他调用synchronized同一对象的方法的线程阻塞(挂起执行),直到第一个线程对该对象完成。

假设您synchronized在对象O上有两个方法m1和m2。如果线程T1在方法m1的执行中间,则线程T2必须等待在同一对象O上调用方法m2,除非线程T1释放了对方法m1的锁定。

类级别锁

线程获取Class与类关联的对象的内部锁。因此,通过与该类的static任何实例的锁不同的锁来控制对类字段的访问。

假设方法m1是static synchrnozed,方法m2也是,static synchronized并且您有两个不同的对象o1和o2。

如果线程T1在对象o1上执行方法m1的过程中,则线程T2必须等待在对象o2上调用方法m2,除非线程T1释放了对方法m1的锁定。